1 /*
   2  * Copyright (c) 2003, 2014, 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 
  27 package sun.security.ssl;
  28 
  29 import java.io.*;
  30 import java.nio.*;
  31 import javax.net.ssl.*;
  32 import javax.crypto.BadPaddingException;
  33 import sun.misc.HexDumpEncoder;
  34 
  35 
  36 /**
  37  * Wrapper class around InputRecord.
  38  *
  39  * Application data is kept external to the InputRecord,
  40  * but handshake data (alert/change_cipher_spec/handshake) will
  41  * be kept internally in the ByteArrayInputStream.
  42  *
  43  * @author Brad Wetmore
  44  */
  45 final class EngineInputRecord extends InputRecord {
  46 
  47     private SSLEngineImpl engine;
  48 
  49     /*
  50      * A dummy ByteBuffer we'll pass back even when the data
  51      * is stored internally.  It'll never actually be used.
  52      */
  53     static private ByteBuffer tmpBB = ByteBuffer.allocate(0);
  54 
  55     /*
  56      * Flag to tell whether the last read/parsed data resides
  57      * internal in the ByteArrayInputStream, or in the external
  58      * buffers.
  59      */
  60     private boolean internalData;
  61 
  62     EngineInputRecord(SSLEngineImpl engine) {
  63         super();
  64         this.engine = engine;
  65     }
  66 
  67     @Override
  68     byte contentType() {
  69         if (internalData) {
  70             return super.contentType();
  71         } else {
  72             return ct_application_data;
  73         }
  74     }
  75 
  76     /*
  77      * Check if there is enough inbound data in the ByteBuffer
  78      * to make a inbound packet.  Look for both SSLv2 and SSLv3.
  79      *
  80      * @return -1 if there are not enough bytes to tell (small header),
  81      */
  82     int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
  83 
  84         /*
  85          * SSLv2 length field is in bytes 0/1
  86          * SSLv3/TLS length field is in bytes 3/4
  87          */
  88         if (buf.remaining() < 5) {
  89             return -1;
  90         }
  91 
  92         int pos = buf.position();
  93         byte byteZero = buf.get(pos);
  94 
  95         int len = 0;
  96 
  97         /*
  98          * If we have already verified previous packets, we can
  99          * ignore the verifications steps, and jump right to the
 100          * determination.  Otherwise, try one last hueristic to
 101          * see if it's SSL/TLS.
 102          */
 103         if (formatVerified ||
 104                 (byteZero == ct_handshake) ||
 105                 (byteZero == ct_alert)) {
 106             /*
 107              * Last sanity check that it's not a wild record
 108              */
 109             ProtocolVersion recordVersion =
 110                 ProtocolVersion.valueOf(buf.get(pos + 1), buf.get(pos + 2));
 111 
 112             // check the record version
 113             checkRecordVersion(recordVersion, false);
 114 
 115             /*
 116              * Reasonably sure this is a V3, disable further checks.
 117              * We can't do the same in the v2 check below, because
 118              * read still needs to parse/handle the v2 clientHello.
 119              */
 120             formatVerified = true;
 121 
 122             /*
 123              * One of the SSLv3/TLS message types.
 124              */
 125             len = ((buf.get(pos + 3) & 0xff) << 8) +
 126                 (buf.get(pos + 4) & 0xff) + headerSize;
 127 
 128         } else {
 129             /*
 130              * Must be SSLv2 or something unknown.
 131              * Check if it's short (2 bytes) or
 132              * long (3) header.
 133              *
 134              * Internals can warn about unsupported SSLv2
 135              */
 136             boolean isShort = ((byteZero & 0x80) != 0);
 137 
 138             if (isShort &&
 139                     ((buf.get(pos + 2) == 1) || buf.get(pos + 2) == 4)) {
 140 
 141                 ProtocolVersion recordVersion =
 142                     ProtocolVersion.valueOf(buf.get(pos + 3), buf.get(pos + 4));
 143 
 144                 // check the record version
 145                 checkRecordVersion(recordVersion, true);
 146 
 147                 /*
 148                  * Client or Server Hello
 149                  */
 150                 int mask = (isShort ? 0x7f : 0x3f);
 151                 len = ((byteZero & mask) << 8) + (buf.get(pos + 1) & 0xff) +
 152                     (isShort ? 2 : 3);
 153 
 154             } else {
 155                 // Gobblygook!
 156                 throw new SSLException(
 157                     "Unrecognized SSL message, plaintext connection?");
 158             }
 159         }
 160 
 161         return len;
 162     }
 163 
 164     /*
 165      * Pass the data down if it's internally cached, otherwise
 166      * do it here.
 167      *
 168      * If internal data, data is decrypted internally.
 169      *
 170      * If external data(app), return a new ByteBuffer with data to
 171      * process.
 172      */
 173     ByteBuffer decrypt(Authenticator authenticator,
 174             CipherBox box, ByteBuffer bb) throws BadPaddingException {
 175 
 176         if (internalData) {
 177             decrypt(authenticator, box);   // MAC is checked during decryption
 178             return tmpBB;
 179         }
 180 
 181         BadPaddingException reservedBPE = null;
 182         int tagLen =
 183             (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
 184         int cipheredLength = bb.remaining();
 185 
 186         if (!box.isNullCipher()) {
 187             try {
 188                 // apply explicit nonce for AEAD/CBC cipher suites if needed
 189                 int nonceSize =
 190                     box.applyExplicitNonce(authenticator, contentType(), bb);
 191 
 192                 // decrypt the content
 193                 if (box.isAEADMode()) {
 194                     // DON'T encrypt the nonce_explicit for AEAD mode
 195                     bb.position(bb.position() + nonceSize);
 196                 }   // The explicit IV for CBC mode can be decrypted.
 197 
 198                 // Note that the CipherBox.decrypt() does not change
 199                 // the capacity of the buffer.
 200                 box.decrypt(bb, tagLen);
 201                 bb.position(nonceSize); // We don't actually remove the nonce.
 202             } catch (BadPaddingException bpe) {
 203                 // RFC 2246 states that decryption_failed should be used
 204                 // for this purpose. However, that allows certain attacks,
 205                 // so we just send bad record MAC. We also need to make
 206                 // sure to always check the MAC to avoid a timing attack
 207                 // for the same issue. See paper by Vaudenay et al and the
 208                 // update in RFC 4346/5246.
 209                 //
 210                 // Failover to message authentication code checking.
 211                 reservedBPE = bpe;
 212             }
 213         }
 214 
 215         // Requires message authentication code for null, stream and block
 216         // cipher suites.
 217         if ((authenticator instanceof MAC) && (tagLen != 0)) {
 218             MAC signer = (MAC)authenticator;
 219             int macOffset = bb.limit() - tagLen;
 220 
 221             // Note that although it is not necessary, we run the same MAC
 222             // computation and comparison on the payload for both stream
 223             // cipher and CBC block cipher.
 224             if (bb.remaining() < tagLen) {
 225                 // negative data length, something is wrong
 226                 if (reservedBPE == null) {
 227                     reservedBPE = new BadPaddingException("bad record");
 228                 }
 229 
 230                 // set offset of the dummy MAC
 231                 macOffset = cipheredLength - tagLen;
 232                 bb.limit(cipheredLength);
 233             }
 234 
 235             // Run MAC computation and comparison on the payload.
 236             if (checkMacTags(contentType(), bb, signer, false)) {
 237                 if (reservedBPE == null) {
 238                     reservedBPE = new BadPaddingException("bad record MAC");
 239                 }
 240             }
 241 
 242             // Run MAC computation and comparison on the remainder.
 243             //
 244             // It is only necessary for CBC block cipher.  It is used to get a
 245             // constant time of MAC computation and comparison on each record.
 246             if (box.isCBCMode()) {
 247                 int remainingLen = calculateRemainingLen(
 248                                         signer, cipheredLength, macOffset);
 249 
 250                 // NOTE: here we use the InputRecord.buf because I did not find
 251                 // an effective way to work on ByteBuffer when its capacity is
 252                 // less than remainingLen.
 253 
 254                 // NOTE: remainingLen may be bigger (less than 1 block of the
 255                 // hash algorithm of the MAC) than the cipheredLength. However,
 256                 // We won't need to worry about it because we always use a
 257                 // maximum buffer for every record.  We need a change here if
 258                 // we use small buffer size in the future.
 259                 if (remainingLen > buf.length) {
 260                     // unlikely to happen, just a placehold
 261                     throw new RuntimeException(
 262                         "Internal buffer capacity error");
 263                 }
 264 
 265                 // Won't need to worry about the result on the remainder. And
 266                 // then we won't need to worry about what's actual data to
 267                 // check MAC tag on.  We start the check from the header of the
 268                 // buffer so that we don't need to construct a new byte buffer.
 269                 checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
 270             }
 271 
 272             bb.limit(macOffset);
 273         }
 274 
 275         // Is it a failover?
 276         if (reservedBPE != null) {
 277             throw reservedBPE;
 278         }
 279 
 280         return bb.slice();
 281     }
 282 
 283     /*
 284      * Run MAC computation and comparison
 285      *
 286      * Please DON'T change the content of the ByteBuffer parameter!
 287      */
 288     private static boolean checkMacTags(byte contentType, ByteBuffer bb,
 289             MAC signer, boolean isSimulated) {
 290 
 291         int position = bb.position();
 292         int tagLen = signer.MAClen();
 293         int lim = bb.limit();
 294         int macData = lim - tagLen;
 295 
 296         bb.limit(macData);
 297         byte[] hash = signer.compute(contentType, bb, isSimulated);
 298         if (hash == null || tagLen != hash.length) {
 299             // Something is wrong with MAC implementation.
 300             throw new RuntimeException("Internal MAC error");
 301         }
 302 
 303         bb.position(macData);
 304         bb.limit(lim);
 305         try {
 306             int[] results = compareMacTags(bb, hash);
 307             return (results[0] != 0);
 308         } finally {
 309             // reset to the data
 310             bb.position(position);
 311             bb.limit(macData);
 312         }
 313     }
 314 
 315     /*
 316      * A constant-time comparison of the MAC tags.
 317      *
 318      * Please DON'T change the content of the ByteBuffer parameter!
 319      */
 320     private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
 321 
 322         // An array of hits is used to prevent Hotspot optimization for
 323         // the purpose of a constant-time check.
 324         int[] results = {0, 0};     // {missed #, matched #}
 325 
 326         // The caller ensures there are enough bytes available in the buffer.
 327         // So we won't need to check the remaining of the buffer.
 328         for (int i = 0; i < tag.length; i++) {
 329             if (bb.get() != tag[i]) {
 330                 results[0]++;       // mismatched bytes
 331             } else {
 332                 results[1]++;       // matched bytes
 333             }
 334         }
 335 
 336         return results;
 337     }
 338 
 339     /*
 340      * Override the actual write below.  We do things this way to be
 341      * consistent with InputRecord.  InputRecord may try to write out
 342      * data to the peer, and *then* throw an Exception.  This forces
 343      * data to be generated/output before the exception is ever
 344      * generated.
 345      */
 346     @Override
 347     void writeBuffer(OutputStream s, byte [] buf, int off, int len)
 348             throws IOException {
 349         /*
 350          * Copy data out of buffer, it's ready to go.
 351          */
 352         ByteBuffer netBB = (ByteBuffer)
 353             (ByteBuffer.allocate(len).put(buf, 0, len).flip());
 354         engine.writer.putOutboundDataSync(netBB);
 355     }
 356 
 357     /*
 358      * Delineate or read a complete packet from src.
 359      *
 360      * If internal data (hs, alert, ccs), the data is read and
 361      * stored internally.
 362      *
 363      * If external data (app), return a new ByteBuffer which points
 364      * to the data to process.
 365      */
 366     ByteBuffer read(ByteBuffer srcBB) throws IOException {
 367         /*
 368          * Could have a src == null/dst == null check here,
 369          * but that was already checked by SSLEngine.unwrap before
 370          * ever attempting to read.
 371          */
 372 
 373         /*
 374          * If we have anything besides application data,
 375          * or if we haven't even done the initial v2 verification,
 376          * we send this down to be processed by the underlying
 377          * internal cache.
 378          */
 379         if (!formatVerified ||
 380                 (srcBB.get(srcBB.position()) != ct_application_data)) {
 381             internalData = true;
 382             read(new ByteBufferInputStream(srcBB), (OutputStream) null);
 383             return tmpBB;
 384         }
 385 
 386         internalData = false;
 387 
 388         int srcPos = srcBB.position();
 389         int srcLim = srcBB.limit();
 390 
 391         ProtocolVersion recordVersion = ProtocolVersion.valueOf(
 392                 srcBB.get(srcPos + 1), srcBB.get(srcPos + 2));
 393 
 394         // check the record version
 395         checkRecordVersion(recordVersion, false);
 396 
 397         /*
 398          * It's really application data.  How much to consume?
 399          * Jump over the header.
 400          */
 401         int len = bytesInCompletePacket(srcBB);
 402         assert(len > 0);
 403 
 404         if (debug != null && Debug.isOn("packet")) {
 405             try {
 406                 HexDumpEncoder hd = new HexDumpEncoder();
 407                 ByteBuffer bb = srcBB.duplicate();  // Use copy of BB
 408                 bb.limit(srcPos + len);
 409 
 410                 System.out.println("[Raw read (bb)]: length = " + len);
 411                 hd.encodeBuffer(bb, System.out);
 412             } catch (IOException e) { }
 413         }
 414 
 415         // Demarcate past header to end of packet.
 416         srcBB.position(srcPos + headerSize);
 417         srcBB.limit(srcPos + len);
 418 
 419         // Protect remainder of buffer, create slice to actually
 420         // operate on.
 421         ByteBuffer bb = srcBB.slice();
 422 
 423         srcBB.position(srcBB.limit());
 424         srcBB.limit(srcLim);
 425 
 426         return bb;
 427     }
 428 }