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.Closeable;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 import java.io.OutputStream;
  32 import java.nio.BufferUnderflowException;
  33 import java.nio.ByteBuffer;
  34 import java.util.concurrent.locks.ReentrantLock;
  35 import javax.crypto.BadPaddingException;
  36 import sun.security.ssl.SSLCipher.SSLReadCipher;
  37 
  38 /**
  39  * {@code InputRecord} takes care of the management of SSL/TLS/DTLS input
  40  * records, including buffering, decryption, handshake messages marshal, etc.
  41  *
  42  * @author David Brownell
  43  */
  44 abstract class InputRecord implements Record, Closeable {
  45     SSLReadCipher       readCipher;
  46     // Needed for KeyUpdate, used after Handshake.Finished
  47     TransportContext    tc;
  48 
  49     final HandshakeHash handshakeHash;
  50     volatile boolean    isClosed;
  51 
  52     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
  53     // and the first message we read is a ClientHello in V2 format, we convert
  54     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
  55     ProtocolVersion     helloVersion;
  56 
  57     // fragment size
  58     int                 fragmentSize;
  59 
  60     final ReentrantLock recordLock = new ReentrantLock();
  61 
  62     InputRecord(HandshakeHash handshakeHash, SSLReadCipher readCipher) {
  63         this.readCipher = readCipher;
  64         this.helloVersion = ProtocolVersion.TLS10;
  65         this.handshakeHash = handshakeHash;
  66         this.isClosed = false;
  67         this.fragmentSize = Record.maxDataSize;
  68     }
  69 
  70     void setHelloVersion(ProtocolVersion helloVersion) {
  71         this.helloVersion = helloVersion;
  72     }
  73 
  74     boolean seqNumIsHuge() {
  75         return (readCipher.authenticator != null) &&
  76                         readCipher.authenticator.seqNumIsHuge();
  77     }
  78 
  79     boolean isEmpty() {
  80         return false;
  81     }
  82 
  83     // apply to DTLS SSLEngine
  84     void expectingFinishFlight() {
  85         // blank
  86     }
  87 
  88     // apply to DTLS SSLEngine
  89     void finishHandshake() {
  90         // blank
  91     }
  92 
  93     /**
  94      * Prevent any more data from being read into this record,
  95      * and flag the record as holding no data.
  96      */
  97     @Override
  98     public void close() throws IOException {
  99         recordLock.lock();
 100         try {
 101             if (!isClosed) {
 102                 isClosed = true;
 103                 readCipher.dispose();
 104             }
 105         } finally {
 106             recordLock.unlock();
 107         }
 108     }
 109 
 110     boolean isClosed() {
 111         return isClosed;
 112     }
 113 
 114     // apply to SSLSocket and SSLEngine
 115     void changeReadCiphers(SSLReadCipher readCipher) {
 116 
 117         /*
 118          * Dispose of any intermediate state in the underlying cipher.
 119          * For PKCS11 ciphers, this will release any attached sessions,
 120          * and thus make finalization faster.
 121          *
 122          * Since MAC's doFinal() is called for every SSL/TLS packet, it's
 123          * not necessary to do the same with MAC's.
 124          */
 125         readCipher.dispose();
 126 
 127         this.readCipher = readCipher;
 128     }
 129 
 130     // change fragment size
 131     void changeFragmentSize(int fragmentSize) {
 132         this.fragmentSize = fragmentSize;
 133     }
 134 
 135     /*
 136      * Check if there is enough inbound data in the ByteBuffer to make
 137      * a inbound packet.
 138      *
 139      * @return -1 if there are not enough bytes to tell (small header),
 140      */
 141     // apply to SSLEngine only
 142     int bytesInCompletePacket(
 143         ByteBuffer[] srcs, int srcsOffset, int srcsLength) throws IOException {
 144 
 145         throw new UnsupportedOperationException("Not supported yet.");
 146     }
 147 
 148     // apply to SSLSocket only
 149     int bytesInCompletePacket() throws IOException {
 150         throw new UnsupportedOperationException();
 151     }
 152 
 153     // apply to SSLSocket only
 154     void setReceiverStream(InputStream inputStream) {
 155         throw new UnsupportedOperationException();
 156     }
 157 
 158     // apply to DTLS SSLEngine only
 159     Plaintext acquirePlaintext()
 160             throws IOException, BadPaddingException {
 161         throw new UnsupportedOperationException();
 162     }
 163 
 164     // read, decrypt and decompress the network record.
 165     //
 166     abstract Plaintext[] decode(ByteBuffer[] srcs, int srcsOffset,
 167             int srcsLength) throws IOException, BadPaddingException;
 168 
 169     // apply to SSLSocket only
 170     void setDeliverStream(OutputStream outputStream) {
 171         throw new UnsupportedOperationException();
 172     }
 173 
 174     // calculate plaintext fragment size
 175     //
 176     // apply to SSLEngine only
 177     int estimateFragmentSize(int packetSize) {
 178         throw new UnsupportedOperationException();
 179     }
 180 
 181     //
 182     // shared helpers
 183     //
 184 
 185     // Not apply to DTLS
 186     static ByteBuffer convertToClientHello(ByteBuffer packet) {
 187         int srcPos = packet.position();
 188 
 189         byte firstByte = packet.get();
 190         byte secondByte = packet.get();
 191         int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2;
 192 
 193         packet.position(srcPos + 3);        // the V2ClientHello record header
 194 
 195         byte majorVersion = packet.get();
 196         byte minorVersion = packet.get();
 197 
 198         int cipherSpecLen = ((packet.get() & 0xFF) << 8) +
 199                              (packet.get() & 0xFF);
 200         int sessionIdLen  = ((packet.get() & 0xFF) << 8) +
 201                              (packet.get() & 0xFF);
 202         int nonceLen      = ((packet.get() & 0xFF) << 8) +
 203                              (packet.get() & 0xFF);
 204 
 205         // Required space for the target SSLv3 ClientHello message.
 206         //  5: record header size
 207         //  4: handshake header size
 208         //  2: ClientHello.client_version
 209         // 32: ClientHello.random
 210         //  1: length byte of ClientHello.session_id
 211         //  2: length bytes of ClientHello.cipher_suites
 212         //  2: empty ClientHello.compression_methods
 213         int requiredSize = 48 + sessionIdLen + ((cipherSpecLen * 2 ) / 3);
 214         byte[] converted = new byte[requiredSize];
 215 
 216         /*
 217          * Build the first part of the V3 record header from the V2 one
 218          * that's now buffered up.  (Lengths are fixed up later).
 219          */
 220         // Note: need not to set the header actually.
 221         converted[0] = ContentType.HANDSHAKE.id;
 222         converted[1] = majorVersion;
 223         converted[2] = minorVersion;
 224         // header [3..4] for handshake message length
 225         // required size is 5;
 226 
 227         /*
 228          * Store the generic V3 handshake header:  4 bytes
 229          */
 230         converted[5] = 1;    // HandshakeMessage.ht_client_hello
 231         // buf [6..8] for length of ClientHello (int24)
 232         // required size += 4;
 233 
 234         /*
 235          * ClientHello header starts with SSL version
 236          */
 237         converted[9] = majorVersion;
 238         converted[10] = minorVersion;
 239         // required size += 2;
 240         int pointer = 11;
 241 
 242         /*
 243          * Copy Random value/nonce ... if less than the 32 bytes of
 244          * a V3 "Random", right justify and zero pad to the left.  Else
 245          * just take the last 32 bytes.
 246          */
 247         int offset = srcPos + 11 + cipherSpecLen + sessionIdLen;
 248 
 249         if (nonceLen < 32) {
 250             for (int i = 0; i < (32 - nonceLen); i++) {
 251                 converted[pointer++] = 0;
 252             }
 253             packet.position(offset);
 254             packet.get(converted, pointer, nonceLen);
 255 
 256             pointer += nonceLen;
 257         } else {
 258             packet.position(offset + nonceLen - 32);
 259             packet.get(converted, pointer, 32);
 260 
 261             pointer += 32;
 262         }
 263 
 264         /*
 265          * Copy session ID (only one byte length!)
 266          */
 267         offset -= sessionIdLen;
 268         converted[pointer++] = (byte)(sessionIdLen & 0xFF);
 269         packet.position(offset);
 270         packet.get(converted, pointer, sessionIdLen);
 271 
 272         /*
 273          * Copy and translate cipher suites ... V2 specs with first byte zero
 274          * are really V3 specs (in the last 2 bytes), just copy those and drop
 275          * the other ones.  Preference order remains unchanged.
 276          *
 277          * Example:  Netscape Navigator 3.0 (exportable) says:
 278          *
 279          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
 280          * 0/6,     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
 281          *
 282          * Microsoft Internet Explorer 3.0 (exportable) supports only
 283          *
 284          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
 285          */
 286         int j;
 287 
 288         offset -= cipherSpecLen;
 289         packet.position(offset);
 290 
 291         j = pointer + 2;
 292         for (int i = 0; i < cipherSpecLen; i += 3) {
 293             if (packet.get() != 0) {
 294                 // Ignore version 2.0 specific cipher suite.  Clients
 295                 // should also include the version 3.0 equivalent in
 296                 // the V2ClientHello message.
 297                 packet.get();           // ignore the 2nd byte
 298                 packet.get();           // ignore the 3rd byte
 299                 continue;
 300             }
 301 
 302             converted[j++] = packet.get();
 303             converted[j++] = packet.get();
 304         }
 305 
 306         j -= pointer + 2;
 307         converted[pointer++] = (byte)((j >>> 8) & 0xFF);
 308         converted[pointer++] = (byte)(j & 0xFF);
 309         pointer += j;
 310 
 311         /*
 312          * Append compression methods (default/null only)
 313          */
 314         converted[pointer++] = 1;
 315         converted[pointer++] = 0;      // Session.compression_null
 316 
 317         /*
 318          * Fill in lengths of the messages we synthesized (nested:
 319          * V3 handshake message within V3 record).
 320          */
 321         // Note: need not to set the header actually.
 322         int fragLen = pointer - 5;                      // TLSPlaintext.length
 323         converted[3] = (byte)((fragLen >>> 8) & 0xFF);
 324         converted[4] = (byte)(fragLen & 0xFF);
 325 
 326         /*
 327          * Handshake.length, length of ClientHello message
 328          */
 329         fragLen = pointer - 9;                          // Handshake.length
 330         converted[6] = (byte)((fragLen >>> 16) & 0xFF);
 331         converted[7] = (byte)((fragLen >>> 8) & 0xFF);
 332         converted[8] = (byte)(fragLen & 0xFF);
 333 
 334         // consume the full record
 335         packet.position(srcPos + recordLen);
 336 
 337         // Need no header bytes.
 338         return ByteBuffer.wrap(converted, 5, pointer - 5);  // 5: header size
 339     }
 340 
 341     // Extract an SSL/(D)TLS record from the specified source buffers.
 342     static ByteBuffer extract(
 343             ByteBuffer[] buffers, int offset, int length, int headerSize) {
 344 
 345         boolean hasFullHeader = false;
 346         int contentLen = -1;
 347         for (int i = offset, j = 0;
 348                 i < (offset + length) && j < headerSize; i++) {
 349             int remains = buffers[i].remaining();
 350             int pos = buffers[i].position();
 351             for (int k = 0; k < remains && j < headerSize; j++, k++) {
 352                 byte b = buffers[i].get(pos + k);
 353                 if (j == (headerSize - 2)) {
 354                     contentLen = ((b & 0xFF) << 8);
 355                 } else if (j == (headerSize -1)) {
 356                     contentLen |= (b & 0xFF);
 357                     hasFullHeader = true;
 358                     break;
 359                 }
 360             }
 361         }
 362 
 363         if (!hasFullHeader) {
 364             throw new BufferUnderflowException();
 365         }
 366 
 367         int packetLen = headerSize + contentLen;
 368         int remains = 0;
 369         for (int i = offset; i < offset + length; i++) {
 370             remains += buffers[i].remaining();
 371             if (remains >= packetLen) {
 372                 break;
 373             }
 374         }
 375 
 376         if (remains < packetLen) {
 377             throw new BufferUnderflowException();
 378         }
 379 
 380         byte[] packet = new byte[packetLen];
 381         int packetOffset = 0;
 382         int packetSpaces = packetLen;
 383         for (int i = offset; i < offset + length; i++) {
 384             if (buffers[i].hasRemaining()) {
 385                 int len = Math.min(packetSpaces, buffers[i].remaining());
 386                 buffers[i].get(packet, packetOffset, len);
 387                 packetOffset += len;
 388                 packetSpaces -= len;
 389             }
 390 
 391             if (packetSpaces <= 0) {
 392                 break;
 393             }
 394         }
 395 
 396         return ByteBuffer.wrap(packet);
 397     }
 398 }