1 /*
   2  * Copyright (c) 1996, 2019, 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 java.util.concurrent.locks.ReentrantLock;
  34 import sun.security.ssl.SSLCipher.SSLWriteCipher;
  35 
  36 /**
  37  * {@code OutputRecord} takes care of the management of SSL/(D)TLS
  38  * output records, including buffering, encryption, handshake
  39  * messages marshal, etc.
  40  *
  41  * @author David Brownell
  42  */
  43 abstract class OutputRecord
  44         extends ByteArrayOutputStream implements Record, Closeable {
  45     SSLWriteCipher              writeCipher;
  46     // Needed for KeyUpdate, used after Handshake.Finished
  47     TransportContext            tc;
  48 
  49     final HandshakeHash         handshakeHash;
  50     boolean                     firstMessage;
  51 
  52     // current protocol version, sent as record version
  53     ProtocolVersion             protocolVersion;
  54 
  55     // version for the ClientHello message. Only relevant if this is a
  56     // client handshake record. If set to ProtocolVersion.SSL20Hello,
  57     // the V3 client hello is converted to V2 format.
  58     ProtocolVersion             helloVersion;
  59 
  60     // Is it the first application record to write?
  61     boolean                     isFirstAppOutputRecord = true;
  62 
  63     // packet size
  64     int                         packetSize;
  65 
  66     // fragment size
  67     int                         fragmentSize;
  68 
  69     // closed or not?
  70     volatile boolean            isClosed;
  71 
  72     final ReentrantLock recordLock = new ReentrantLock();
  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 final int[] V3toV2CipherMap1 =
  79         {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
  80     private static final int[] V3toV2CipherMap3 =
  81         {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
  82     private static final byte[] HANDSHAKE_MESSAGE_KEY_UPDATE =
  83         {SSLHandshake.KEY_UPDATE.id, 0x00, 0x00, 0x01, 0x00};
  84 
  85     OutputRecord(HandshakeHash handshakeHash, SSLWriteCipher writeCipher) {
  86         this.writeCipher = writeCipher;
  87         this.firstMessage = true;
  88         this.fragmentSize = Record.maxDataSize;
  89 
  90         this.handshakeHash = handshakeHash;
  91 
  92         // Please set packetSize and protocolVersion in the implementation.
  93     }
  94 
  95     void setVersion(ProtocolVersion protocolVersion) {
  96         recordLock.lock();
  97         try {
  98             this.protocolVersion = protocolVersion;
  99         } finally {
 100             recordLock.unlock();
 101         }
 102     }
 103 
 104     /*
 105      * Updates helloVersion of this record.
 106      */
 107     void setHelloVersion(ProtocolVersion helloVersion) {
 108         recordLock.lock();
 109         try {
 110             this.helloVersion = helloVersion;
 111         } finally {
 112             recordLock.unlock();
 113         }
 114     }
 115 
 116     /*
 117      * Return true iff the record is empty -- to avoid doing the work
 118      * of sending empty records over the network.
 119      */
 120     boolean isEmpty() {
 121         return false;
 122     }
 123 
 124     boolean seqNumIsHuge() {
 125         recordLock.lock();
 126         try {
 127             return (writeCipher.authenticator != null) &&
 128                         writeCipher.authenticator.seqNumIsHuge();
 129         } finally {
 130             recordLock.unlock();
 131         }
 132     }
 133 
 134     // SSLEngine and SSLSocket
 135     abstract void encodeAlert(byte level, byte description) throws IOException;
 136 
 137     // SSLEngine and SSLSocket
 138     abstract void encodeHandshake(byte[] buffer,
 139             int offset, int length) throws IOException;
 140 
 141     // SSLEngine and SSLSocket
 142     abstract void encodeChangeCipherSpec() throws IOException;
 143 
 144     // apply to SSLEngine only
 145     Ciphertext encode(
 146         ByteBuffer[] srcs, int srcsOffset, int srcsLength,
 147         ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException {
 148 
 149         throw new UnsupportedOperationException();
 150     }
 151 
 152     // apply to SSLEngine only
 153     void encodeV2NoCipher() throws IOException {
 154         throw new UnsupportedOperationException();
 155     }
 156 
 157     // apply to SSLSocket only
 158     void deliver(
 159             byte[] source, int offset, int length) throws IOException {
 160         throw new UnsupportedOperationException();
 161     }
 162 
 163     // apply to SSLSocket only
 164     void setDeliverStream(OutputStream outputStream) {
 165         throw new UnsupportedOperationException();
 166     }
 167 
 168     // Change write ciphers, may use change_cipher_spec record.
 169     void changeWriteCiphers(SSLWriteCipher writeCipher,
 170             boolean useChangeCipherSpec) throws IOException {
 171         recordLock.lock();
 172         try {
 173             if (isClosed()) {
 174                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 175                     SSLLogger.warning("outbound has closed, ignore outbound " +
 176                         "change_cipher_spec message");
 177                 }
 178                 return;
 179             }
 180 
 181             if (useChangeCipherSpec) {
 182                 encodeChangeCipherSpec();
 183             }
 184 
 185             /*
 186              * Dispose of any intermediate state in the underlying cipher.
 187              * For PKCS11 ciphers, this will release any attached sessions,
 188              * and thus make finalization faster.
 189              *
 190              * Since MAC's doFinal() is called for every SSL/TLS packet, it's
 191              * not necessary to do the same with MAC's.
 192              */
 193             writeCipher.dispose();
 194 
 195             this.writeCipher = writeCipher;
 196             this.isFirstAppOutputRecord = true;
 197         } finally {
 198             recordLock.unlock();
 199         }
 200     }
 201 
 202     // Change write ciphers using key_update handshake message.
 203     void changeWriteCiphers(SSLWriteCipher writeCipher,
 204             byte keyUpdateRequest) throws IOException {
 205         recordLock.lock();
 206         try {
 207             if (isClosed()) {
 208                 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 209                     SSLLogger.warning("outbound has closed, ignore outbound " +
 210                         "key_update handshake message");
 211                 }
 212                 return;
 213             }
 214 
 215             // encode the handshake message, KeyUpdate
 216             byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone();
 217             hm[hm.length - 1] = keyUpdateRequest;
 218             encodeHandshake(hm, 0, hm.length);
 219             flush();
 220 
 221             // Dispose of any intermediate state in the underlying cipher.
 222             writeCipher.dispose();
 223 
 224             this.writeCipher = writeCipher;
 225             this.isFirstAppOutputRecord = true;
 226         } finally {
 227             recordLock.unlock();
 228         }
 229     }
 230 
 231     void changePacketSize(int packetSize) {
 232         recordLock.lock();
 233         try {
 234             this.packetSize = packetSize;
 235         } finally {
 236             recordLock.unlock();
 237         }
 238     }
 239 
 240     void changeFragmentSize(int fragmentSize) {
 241         recordLock.lock();
 242         try {
 243             this.fragmentSize = fragmentSize;
 244         } finally {
 245             recordLock.unlock();
 246         }
 247     }
 248 
 249     int getMaxPacketSize() {
 250         recordLock.lock();
 251         try {
 252             return packetSize;
 253         } finally {
 254             recordLock.unlock();
 255         }
 256     }
 257 
 258     // apply to DTLS SSLEngine
 259     void initHandshaker() {
 260         // blank
 261     }
 262 
 263     // apply to DTLS SSLEngine
 264     void finishHandshake() {
 265         // blank
 266     }
 267 
 268     // apply to DTLS SSLEngine
 269     void launchRetransmission() {
 270         // blank
 271     }
 272 
 273     @Override
 274     public void close() throws IOException {
 275         recordLock.lock();
 276         try {
 277             if (isClosed) {
 278                 return;
 279             }
 280 
 281             isClosed = true;
 282             writeCipher.dispose();
 283         } finally {
 284             recordLock.unlock();
 285         }
 286     }
 287 
 288     boolean isClosed() {
 289         return isClosed;
 290     }
 291 
 292     //
 293     // shared helpers
 294     //
 295 
 296     // Encrypt a fragment and wrap up a record.
 297     //
 298     // To be consistent with the spec of SSLEngine.wrap() methods, the
 299     // destination ByteBuffer's position is updated to reflect the amount
 300     // of data produced.  The limit remains the same.
 301     static long encrypt(
 302             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 303             int headerOffset, int dstLim, int headerSize,
 304             ProtocolVersion protocolVersion) {
 305         boolean isDTLS = protocolVersion.isDTLS;
 306         if (isDTLS) {
 307             if (protocolVersion.useTLS13PlusSpec()) {
 308                 return d13Encrypt(encCipher,
 309                         contentType, destination, headerOffset,
 310                         dstLim, headerSize, protocolVersion);
 311             } else {
 312                 return d10Encrypt(encCipher,
 313                         contentType, destination, headerOffset,
 314                         dstLim, headerSize, protocolVersion);
 315             }
 316         } else {
 317             if (protocolVersion.useTLS13PlusSpec()) {
 318                 return t13Encrypt(encCipher,
 319                         contentType, destination, headerOffset,
 320                         dstLim, headerSize, protocolVersion);
 321             } else {
 322                 return t10Encrypt(encCipher,
 323                         contentType, destination, headerOffset,
 324                         dstLim, headerSize, protocolVersion);
 325             }
 326         }
 327     }
 328 
 329     private static long d13Encrypt(
 330             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 331             int headerOffset, int dstLim, int headerSize,
 332             ProtocolVersion protocolVersion) {
 333         throw new UnsupportedOperationException("Not supported yet.");
 334     }
 335 
 336     private static long d10Encrypt(
 337             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 338             int headerOffset, int dstLim, int headerSize,
 339             ProtocolVersion protocolVersion) {
 340         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 341         encCipher.encrypt(contentType, destination);
 342 
 343         // Finish out the record header.
 344         int fragLen = destination.limit() - headerOffset - headerSize;
 345 
 346         destination.put(headerOffset, contentType);         // content type
 347         destination.put(headerOffset + 1, protocolVersion.major);
 348         destination.put(headerOffset + 2, protocolVersion.minor);
 349 
 350         // epoch and sequence_number
 351         destination.put(headerOffset + 3, sequenceNumber[0]);
 352         destination.put(headerOffset + 4, sequenceNumber[1]);
 353         destination.put(headerOffset + 5, sequenceNumber[2]);
 354         destination.put(headerOffset + 6, sequenceNumber[3]);
 355         destination.put(headerOffset + 7, sequenceNumber[4]);
 356         destination.put(headerOffset + 8, sequenceNumber[5]);
 357         destination.put(headerOffset + 9, sequenceNumber[6]);
 358         destination.put(headerOffset + 10, sequenceNumber[7]);
 359 
 360         // fragment length
 361         destination.put(headerOffset + 11, (byte)(fragLen >> 8));
 362         destination.put(headerOffset + 12, (byte)fragLen);
 363 
 364         // Update destination position to reflect the amount of data produced.
 365         destination.position(destination.limit());
 366 
 367         return Authenticator.toLong(sequenceNumber);
 368     }
 369 
 370     private static long t13Encrypt(
 371             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 372             int headerOffset, int dstLim, int headerSize,
 373             ProtocolVersion protocolVersion) {
 374         if (!encCipher.isNullCipher()) {
 375             // inner plaintext, using zero length padding.
 376             int endOfPt = destination.limit();
 377             destination.limit(endOfPt + 1);
 378             destination.put(endOfPt, contentType);
 379         }
 380 
 381         // use the right TLSCiphertext.opaque_type and legacy_record_version
 382         ProtocolVersion pv = protocolVersion;
 383         if (!encCipher.isNullCipher()) {
 384             pv = ProtocolVersion.TLS12;
 385             contentType = ContentType.APPLICATION_DATA.id;
 386         } else if (protocolVersion.useTLS13PlusSpec()) {
 387             pv = ProtocolVersion.TLS12;
 388         }
 389 
 390         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 391         encCipher.encrypt(contentType, destination);
 392 
 393         // Finish out the record header.
 394         int fragLen = destination.limit() - headerOffset - headerSize;
 395         destination.put(headerOffset, contentType);
 396         destination.put(headerOffset + 1, pv.major);
 397         destination.put(headerOffset + 2, pv.minor);
 398 
 399         // fragment length
 400         destination.put(headerOffset + 3, (byte)(fragLen >> 8));
 401         destination.put(headerOffset + 4, (byte)fragLen);
 402 
 403         // Update destination position to reflect the amount of data produced.
 404         destination.position(destination.limit());
 405 
 406         return Authenticator.toLong(sequenceNumber);
 407     }
 408 
 409     private static long t10Encrypt(
 410             SSLWriteCipher encCipher, byte contentType, ByteBuffer destination,
 411             int headerOffset, int dstLim, int headerSize,
 412             ProtocolVersion protocolVersion) {
 413         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 414         encCipher.encrypt(contentType, destination);
 415 
 416         // Finish out the record header.
 417         int fragLen = destination.limit() - headerOffset - headerSize;
 418 
 419         destination.put(headerOffset, contentType);         // content type
 420         destination.put(headerOffset + 1, protocolVersion.major);
 421         destination.put(headerOffset + 2, protocolVersion.minor);
 422 
 423         // fragment length
 424         destination.put(headerOffset + 3, (byte)(fragLen >> 8));
 425         destination.put(headerOffset + 4, (byte)fragLen);
 426 
 427         // Update destination position to reflect the amount of data produced.
 428         destination.position(destination.limit());
 429 
 430         return Authenticator.toLong(sequenceNumber);
 431     }
 432 
 433     // Encrypt a fragment and wrap up a record.
 434     //
 435     // Uses the internal expandable buf variable and the current
 436     // protocolVersion variable.
 437     long encrypt(
 438             SSLWriteCipher encCipher, byte contentType, int headerSize) {
 439         if (protocolVersion.useTLS13PlusSpec()) {
 440             return t13Encrypt(encCipher, contentType, headerSize);
 441         } else {
 442             return t10Encrypt(encCipher, contentType, headerSize);
 443         }
 444     }
 445 
 446     private static final class T13PaddingHolder {
 447         private static final byte[] zeros = new byte[16];
 448     }
 449 
 450     private long t13Encrypt(
 451             SSLWriteCipher encCipher, byte contentType, int headerSize) {
 452         if (!encCipher.isNullCipher()) {
 453             // inner plaintext
 454             write(contentType);
 455             write(T13PaddingHolder.zeros, 0, T13PaddingHolder.zeros.length);
 456         }
 457 
 458         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 459         int position = headerSize;
 460         int contentLen = count - position;
 461 
 462         // ensure the capacity
 463         int requiredPacketSize =
 464                 encCipher.calculatePacketSize(contentLen, headerSize);
 465         if (requiredPacketSize > buf.length) {
 466             byte[] newBuf = new byte[requiredPacketSize];
 467             System.arraycopy(buf, 0, newBuf, 0, count);
 468             buf = newBuf;
 469         }
 470 
 471         // use the right TLSCiphertext.opaque_type and legacy_record_version
 472         ProtocolVersion pv = protocolVersion;
 473         if (!encCipher.isNullCipher()) {
 474             pv = ProtocolVersion.TLS12;
 475             contentType = ContentType.APPLICATION_DATA.id;
 476         } else {
 477             pv = ProtocolVersion.TLS12;
 478         }
 479 
 480         ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen);
 481         count = headerSize + encCipher.encrypt(contentType, destination);
 482 
 483         // Fill out the header, write it and the message.
 484         int fragLen = count - headerSize;
 485 
 486         buf[0] = contentType;
 487         buf[1] = pv.major;
 488         buf[2] = pv.minor;
 489         buf[3] = (byte)((fragLen >> 8) & 0xFF);
 490         buf[4] = (byte)(fragLen & 0xFF);
 491 
 492         return Authenticator.toLong(sequenceNumber);
 493     }
 494 
 495     private long t10Encrypt(
 496             SSLWriteCipher encCipher, byte contentType, int headerSize) {
 497         byte[] sequenceNumber = encCipher.authenticator.sequenceNumber();
 498         int position = headerSize + writeCipher.getExplicitNonceSize();
 499         int contentLen = count - position;
 500 
 501         // ensure the capacity
 502         int requiredPacketSize =
 503                 encCipher.calculatePacketSize(contentLen, headerSize);
 504         if (requiredPacketSize > buf.length) {
 505             byte[] newBuf = new byte[requiredPacketSize];
 506             System.arraycopy(buf, 0, newBuf, 0, count);
 507             buf = newBuf;
 508         }
 509         ByteBuffer destination = ByteBuffer.wrap(buf, position, contentLen);
 510         count = headerSize + encCipher.encrypt(contentType, destination);
 511 
 512         // Fill out the header, write it and the message.
 513         int fragLen = count - headerSize;
 514         buf[0] = contentType;
 515         buf[1] = protocolVersion.major;
 516         buf[2] = protocolVersion.minor;
 517         buf[3] = (byte)((fragLen >> 8) & 0xFF);
 518         buf[4] = (byte)(fragLen & 0xFF);
 519 
 520         return Authenticator.toLong(sequenceNumber);
 521     }
 522 
 523     static ByteBuffer encodeV2ClientHello(
 524             byte[] fragment, int offset, int length) throws IOException {
 525         int v3SessIdLenOffset = offset + 34;      //  2: client_version
 526                                                   // 32: random
 527 
 528         int v3SessIdLen = fragment[v3SessIdLenOffset];
 529         int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen;
 530         int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) +
 531                        (fragment[v3CSLenOffset + 1] & 0xff);
 532         int cipherSpecs = v3CSLen / 2;        // 2: cipher spec size
 533 
 534         // Estimate the max V2ClientHello message length
 535         //
 536         // 11: header size
 537         // (cipherSpecs * 6): cipher_specs
 538         //    6: one cipher suite may need 6 bytes, see V3toV2CipherSuite.
 539         // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
 540         //    signaling cipher suite
 541         // 32: challenge size
 542         int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32;
 543 
 544         // Create a ByteBuffer backed by an accessible byte array.
 545         byte[] dstBytes = new byte[v2MaxMsgLen];
 546         ByteBuffer dstBuf = ByteBuffer.wrap(dstBytes);
 547 
 548         /*
 549          * Copy over the cipher specs. We don't care about actually
 550          * translating them for use with an actual V2 server since
 551          * we only talk V3.  Therefore, just copy over the V3 cipher
 552          * spec values with a leading 0.
 553          */
 554         int v3CSOffset = v3CSLenOffset + 2;   // skip length field
 555         int v2CSLen = 0;
 556 
 557         dstBuf.position(11);
 558         boolean containsRenegoInfoSCSV = false;
 559         for (int i = 0; i < cipherSpecs; i++) {
 560             byte byte1, byte2;
 561 
 562             byte1 = fragment[v3CSOffset++];
 563             byte2 = fragment[v3CSOffset++];
 564             v2CSLen += V3toV2CipherSuite(dstBuf, byte1, byte2);
 565             if (!containsRenegoInfoSCSV &&
 566                     byte1 == (byte)0x00 && byte2 == (byte)0xFF) {
 567                 containsRenegoInfoSCSV = true;
 568             }
 569         }
 570 
 571         if (!containsRenegoInfoSCSV) {
 572             v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF);
 573         }
 574 
 575         /*
 576          * Copy in the nonce.
 577          */
 578         dstBuf.put(fragment, (offset + 2), 32);
 579 
 580         /*
 581          * Build the first part of the V3 record header from the V2 one
 582          * that's now buffered up.  (Lengths are fixed up later).
 583          */
 584         int msgLen = dstBuf.position() - 2;   // Exclude the legth field itself
 585         dstBuf.position(0);
 586         dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF)));  // pos: 0
 587         dstBuf.put((byte)(msgLen & 0xFF));                   // pos: 1
 588         dstBuf.put(SSLHandshake.CLIENT_HELLO.id);            // pos: 2
 589         dstBuf.put(fragment[offset]);         // major version, pos: 3
 590         dstBuf.put(fragment[offset + 1]);     // minor version, pos: 4
 591         dstBuf.put((byte)(v2CSLen >>> 8));                   // pos: 5
 592         dstBuf.put((byte)(v2CSLen & 0xFF));                  // pos: 6
 593         dstBuf.put((byte)0x00);           // session_id_length, pos: 7
 594         dstBuf.put((byte)0x00);                              // pos: 8
 595         dstBuf.put((byte)0x00);           // challenge_length,  pos: 9
 596         dstBuf.put((byte)32);                                // pos: 10
 597 
 598         dstBuf.position(0);
 599         dstBuf.limit(msgLen + 2);
 600 
 601         return dstBuf;
 602     }
 603 
 604     private static int V3toV2CipherSuite(ByteBuffer dstBuf,
 605             byte byte1, byte byte2) {
 606         dstBuf.put((byte)0);
 607         dstBuf.put(byte1);
 608         dstBuf.put(byte2);
 609 
 610         if (((byte2 & 0xff) > 0xA) || (V3toV2CipherMap1[byte2] == -1)) {
 611             return 3;
 612         }
 613 
 614         dstBuf.put((byte)V3toV2CipherMap1[byte2]);
 615         dstBuf.put((byte)0);
 616         dstBuf.put((byte)V3toV2CipherMap3[byte2]);
 617 
 618         return 6;
 619     }
 620 }