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

Print this page




   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 
  32 import javax.crypto.BadPaddingException;
  33 
  34 import javax.net.ssl.*;
  35 
  36 import sun.misc.HexDumpEncoder;
  37 
  38 
  39 /**
  40  * SSL 3.0 records, as pulled off a TCP stream.  Input records are
  41  * basically buffers tied to a particular input stream ... a layer
  42  * above this must map these records into the model of a continuous
  43  * stream of data.
  44  *
  45  * Since this returns SSL 3.0 records, it's the layer that needs to
  46  * map SSL 2.0 style handshake records into SSL 3.0 ones for those
  47  * "old" clients that interop with both V2 and V3 servers.  Not as
  48  * pretty as might be desired.
  49  *
  50  * NOTE:  During handshaking, each message must be hashed to support
  51  * verification that the handshake process wasn't compromised.
  52  *
  53  * @author David Brownell
  54  */
  55 class InputRecord extends ByteArrayInputStream implements Record {
  56 
  57     private HandshakeHash       handshakeHash;
  58     private int                 lastHashed;
  59     boolean                     formatVerified = true;  // SSLv2 ruled out?
  60     private boolean             isClosed;
  61     private boolean             appDataValid;
  62 






  63     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
  64     // and the first message we read is a ClientHello in V2 format, we convert
  65     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
  66     private ProtocolVersion     helloVersion;
  67 
  68     /* Class and subclass dynamic debugging support */
  69     static final Debug debug = Debug.getInstance("ssl");
  70 
  71     /* The existing record length */
  72     private int exlen;




  73 
  74     /* V2 handshake message */
  75     private byte v2Buf[];

  76 




  77     /*
  78      * Construct the record to hold the maximum sized input record.
  79      * Data will be filled in separately.
  80      *
  81      * The structure of the byte buffer looks like:


























































  82      *
  83      *     |--------+---------+---------------------------------|
  84      *     | header |   IV    | content, MAC/TAG, padding, etc. |
  85      *     | headerPlusIVSize |














  86      *
  87      * header: the header of an SSL records
  88      * IV:     the optional IV/nonce field, it is only required for block
  89      *         (TLS 1.1 or later) and AEAD cipher suites.
  90      *
  91      */
  92     InputRecord() {
  93         super(new byte[maxRecordSize]);
  94         setHelloVersion(ProtocolVersion.DEFAULT_HELLO);
  95         pos = headerSize;
  96         count = headerSize;
  97         lastHashed = count;
  98         exlen = 0;
  99         v2Buf = null;
 100     }
 101 
 102     void setHelloVersion(ProtocolVersion helloVersion) {
 103         this.helloVersion = helloVersion;

 104     }
 105 
 106     ProtocolVersion getHelloVersion() {
 107         return helloVersion;





 108     }
 109 




































































 110     /*
 111      * Enable format checks if initial handshaking hasn't completed

 112      */
 113     void enableFormatChecks() {
 114         formatVerified = false;
 115     }



 116 
 117     // return whether the data in this record is valid, decrypted data
 118     boolean isAppDataValid() {
 119         return appDataValid;






















 120     }


 121 
 122     void setAppDataValid(boolean value) {
 123         appDataValid = value;




 124     }
 125 
 126     /*
 127      * Return the content type of the record.
 128      */
 129     byte contentType() {
 130         return buf[0];































 131     }
 132 









 133     /*
 134      * For handshaking, we need to be able to hash every byte above the
 135      * record marking layer.  This is where we're guaranteed to see those
 136      * bytes, so this is where we can hash them ... especially in the
 137      * case of hashing the initial V2 message!
 138      */
 139     void setHandshakeHash(HandshakeHash handshakeHash) {
 140         this.handshakeHash = handshakeHash;























 141     }
 142 
 143     HandshakeHash getHandshakeHash() {
 144         return handshakeHash;


 145     }
 146 
 147     void decrypt(Authenticator authenticator,
 148             CipherBox box) throws BadPaddingException {


 149         BadPaddingException reservedBPE = null;
 150         int tagLen =
 151             (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
 152         int cipheredLength = count - headerSize;
 153 
 154         if (!box.isNullCipher()) {
 155             try {
 156                 // apply explicit nonce for AEAD/CBC cipher suites if needed
 157                 int nonceSize = box.applyExplicitNonce(authenticator,
 158                         contentType(), buf, headerSize, cipheredLength);
 159                 pos = headerSize + nonceSize;
 160                 lastHashed = pos;   // don't digest the explicit nonce
 161 
 162                 // decrypt the content
 163                 int offset = headerSize;
 164                 if (box.isAEADMode()) {
 165                     // DON'T encrypt the nonce_explicit for AEAD mode
 166                     offset += nonceSize;
 167                 }   // The explicit IV for CBC mode can be decrypted.
 168 
 169                 // Note that the CipherBox.decrypt() does not change
 170                 // the capacity of the buffer.
 171                 count = offset +
 172                     box.decrypt(buf, offset, count - offset, tagLen);
 173 
 174                 // Note that we don't remove the nonce from the buffer.
 175             } catch (BadPaddingException bpe) {
 176                 // RFC 2246 states that decryption_failed should be used
 177                 // for this purpose. However, that allows certain attacks,
 178                 // so we just send bad record MAC. We also need to make
 179                 // sure to always check the MAC to avoid a timing attack
 180                 // for the same issue. See paper by Vaudenay et al and the
 181                 // update in RFC 4346/5246.
 182                 //
 183                 // Failover to message authentication code checking.
 184                 reservedBPE = bpe;
 185             }
 186         }
 187 
 188         // Requires message authentication code for null, stream and block
 189         // cipher suites.
 190         if (authenticator instanceof MAC && tagLen != 0) {
 191             MAC signer = (MAC)authenticator;
 192             int macOffset = count - tagLen;
 193             int contentLen = macOffset - pos;
 194 
 195             // Note that although it is not necessary, we run the same MAC
 196             // computation and comparison on the payload for both stream
 197             // cipher and CBC block cipher.
 198             if (contentLen < 0) {
 199                 // negative data length, something is wrong
 200                 if (reservedBPE == null) {
 201                     reservedBPE = new BadPaddingException("bad record");
 202                 }
 203 
 204                 // set offset of the dummy MAC
 205                 macOffset = headerSize + cipheredLength - tagLen;
 206                 contentLen = macOffset - headerSize;
 207             }
 208 
 209             count -= tagLen;  // Set the count before any MAC checking
 210                               // exception occurs, so that the following
 211                               // process can read the actual decrypted
 212                               // content (minus the MAC) in the fragment
 213                               // if necessary.
 214 
 215             // Run MAC computation and comparison on the payload.
 216             if (checkMacTags(contentType(),
 217                     buf, pos, contentLen, signer, false)) {

 218                 if (reservedBPE == null) {
 219                     reservedBPE = new BadPaddingException("bad record MAC");
 220                 }
 221             }
 222 
 223             // Run MAC computation and comparison on the remainder.
 224             //
 225             // It is only necessary for CBC block cipher.  It is used to get a
 226             // constant time of MAC computation and comparison on each record.
 227             if (box.isCBCMode()) {
 228                 int remainingLen = calculateRemainingLen(
 229                                         signer, cipheredLength, contentLen);
 230 
 231                 // NOTE: remainingLen may be bigger (less than 1 block of the
 232                 // hash algorithm of the MAC) than the cipheredLength. However,
 233                 // We won't need to worry about it because we always use a
 234                 // maximum buffer for every record.  We need a change here if
 235                 // we use small buffer size in the future.
 236                 if (remainingLen > buf.length) {
 237                     // unlikely to happen, just a placehold
 238                     throw new RuntimeException(
 239                         "Internal buffer capacity error");
 240                 }
 241 
 242                 // Won't need to worry about the result on the remainder. And
 243                 // then we won't need to worry about what's actual data to
 244                 // check MAC tag on.  We start the check from the header of the
 245                 // buffer so that we don't need to construct a new byte buffer.
 246                 checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
 247             }
 248         }
 249 
 250         // Is it a failover?
 251         if (reservedBPE != null) {
 252             throw reservedBPE;
 253         }


 254     }
 255 
 256     /*
 257      * Run MAC computation and comparison
 258      *























































 259      * Please DON'T change the content of the byte buffer parameter!
 260      */
 261     static boolean checkMacTags(byte contentType, byte[] buffer,
 262             int offset, int contentLen, MAC signer, boolean isSimulated) {
 263 
 264         int tagLen = signer.MAClen();
 265         byte[] hash = signer.compute(
 266                 contentType, buffer, offset, contentLen, isSimulated);
 267         if (hash == null || tagLen != hash.length) {
 268             // Something is wrong with MAC implementation.
 269             throw new RuntimeException("Internal MAC error");
 270         }
 271 
 272         int[] results = compareMacTags(buffer, offset + contentLen, hash);
 273         return (results[0] != 0);
 274     }
 275 
 276     /*
 277      * A constant-time comparison of the MAC tags.
 278      *
 279      * Please DON'T change the content of the byte buffer parameter!
 280      */
 281     private static int[] compareMacTags(


 287 
 288         // The caller ensures there are enough bytes available in the buffer.
 289         // So we won't need to check the length of the buffer.
 290         for (int i = 0; i < tag.length; i++) {
 291             if (buffer[offset + i] != tag[i]) {
 292                 results[0]++;       // mismatched bytes
 293             } else {
 294                 results[1]++;       // matched bytes
 295             }
 296         }
 297 
 298         return results;
 299     }
 300 
 301     /*
 302      * Calculate the length of a dummy buffer to run MAC computation
 303      * and comparison on the remainder.
 304      *
 305      * The caller MUST ensure that the fullLen is not less than usedLen.
 306      */
 307     static int calculateRemainingLen(
 308             MAC signer, int fullLen, int usedLen) {
 309 
 310         int blockLen = signer.hashBlockLen();
 311         int minimalPaddingLen = signer.minimalPaddingLen();
 312 
 313         // (blockLen - minimalPaddingLen) is the maximum message size of
 314         // the last block of hash function operation. See FIPS 180-4, or
 315         // MD5 specification.
 316         fullLen += 13 - (blockLen - minimalPaddingLen);
 317         usedLen += 13 - (blockLen - minimalPaddingLen);
 318 
 319         // Note: fullLen is always not less than usedLen, and blockLen
 320         // is always bigger than minimalPaddingLen, so we don't worry
 321         // about negative values. 0x01 is added to the result to ensure
 322         // that the return value is positive.  The extra one byte does
 323         // not impact the overall MAC compression function evaluations.
 324         return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
 325                 Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen();
 326     }
 327 
 328     /*
 329      * Well ... hello_request messages are _never_ hashed since we can't
 330      * know when they'd appear in the sequence.
 331      */
 332     void ignore(int bytes) {
 333         if (bytes > 0) {
 334             pos += bytes;
 335             lastHashed = pos;
 336         }
 337     }
 338 
 339     /*
 340      * We hash the (plaintext) we've processed, but only on demand.
 341      *
 342      * There is one place where we want to access the hash in the middle
 343      * of a record:  client cert message gets hashed, and part of the
 344      * same record is the client cert verify message which uses that hash.
 345      * So we track how much we've read and hashed.
 346      */
 347     void doHashes() {
 348         int len = pos - lastHashed;
 349 
 350         if (len > 0) {
 351             hashInternal(buf, lastHashed, len);
 352             lastHashed = pos;
 353         }
 354     }
 355 
 356     /*
 357      * Need a helper function so we can hash the V2 hello correctly
 358      */
 359     private void hashInternal(byte databuf [], int offset, int len) {
 360         if (debug != null && Debug.isOn("data")) {
 361             try {
 362                 HexDumpEncoder hd = new HexDumpEncoder();
 363 
 364                 System.out.println("[read] MD5 and SHA1 hashes:  len = "
 365                     + len);
 366                 hd.encodeBuffer(new ByteArrayInputStream(databuf, offset, len),
 367                     System.out);
 368             } catch (IOException e) { }
 369         }
 370         handshakeHash.update(databuf, offset, len);
 371     }
 372 
 373 
 374     /*
 375      * Handshake messages may cross record boundaries.  We "queue"
 376      * these in big buffers if we need to cope with this problem.
 377      * This is not anticipated to be a common case; if this turns
 378      * out to be wrong, this can readily be sped up.
 379      */
 380     void queueHandshake(InputRecord r) throws IOException {
 381         int len;
 382 
 383         /*
 384          * Hash any data that's read but unhashed.
 385          */
 386         doHashes();
 387 
 388         /*
 389          * Move any unread data to the front of the buffer,
 390          * flagging it all as unhashed.
 391          */
 392         if (pos > headerSize) {
 393             len = count - pos;
 394             if (len != 0) {
 395                 System.arraycopy(buf, pos, buf, headerSize, len);
 396             }
 397             pos = headerSize;
 398             lastHashed = pos;
 399             count = headerSize + len;
 400         }
 401 
 402         /*
 403          * Grow "buf" if needed
 404          */
 405         len = r.available() + count;
 406         if (buf.length < len) {
 407             byte        newbuf [];
 408 
 409             newbuf = new byte [len];
 410             System.arraycopy(buf, 0, newbuf, 0, count);
 411             buf = newbuf;
 412         }
 413 
 414         /*
 415          * Append the new buffer to this one.
 416          */
 417         System.arraycopy(r.buf, r.pos, buf, count, len - count);
 418         count = len;
 419 
 420         /*
 421          * Adjust lastHashed; important for now with clients which
 422          * send SSL V2 client hellos.  This will go away eventually,
 423          * by buffer code cleanup.
 424          */
 425         len = r.lastHashed - r.pos;
 426         if (pos == headerSize) {
 427             lastHashed += len;
 428         } else {
 429             throw new SSLProtocolException("?? confused buffer hashing ??");
 430         }
 431         // we've read the record, advance the pointers
 432         r.pos = r.count;
 433     }
 434 
 435 
 436     /**
 437      * Prevent any more data from being read into this record,
 438      * and flag the record as holding no data.
 439      */
 440     @Override
 441     public void close() {
 442         appDataValid = false;
 443         isClosed = true;
 444         mark = 0;
 445         pos = 0;
 446         count = 0;
 447     }
 448 
 449 
 450     /*
 451      * We may need to send this SSL v2 "No Cipher" message back, if we
 452      * are faced with an SSLv2 "hello" that's not saying "I talk v3".
 453      * It's the only one documented in the V2 spec as a fatal error.
 454      */
 455     private static final byte[] v2NoCipher = {
 456         (byte)0x80, (byte)0x03, // unpadded 3 byte record
 457         (byte)0x00,             // ... error message
 458         (byte)0x00, (byte)0x01  // ... NO_CIPHER error
 459     };
 460 
 461     private int readFully(InputStream s, byte b[], int off, int len)
 462             throws IOException {
 463         int n = 0;
 464         while (n < len) {
 465             int readLen = s.read(b, off + n, len - n);
 466             if (readLen < 0) {
 467                 return readLen;
 468             }
 469 
 470             if (debug != null && Debug.isOn("packet")) {
 471                 try {
 472                     HexDumpEncoder hd = new HexDumpEncoder();
 473                     ByteBuffer bb = ByteBuffer.wrap(b, off + n, readLen);
 474 
 475                     System.out.println("[Raw read]: length = " +
 476                         bb.remaining());
 477                     hd.encodeBuffer(bb, System.out);
 478                 } catch (IOException e) { }
 479             }
 480 
 481             n += readLen;
 482             exlen += readLen;
 483         }
 484 
 485         return n;
 486     }
 487 
 488     /*
 489      * Read the SSL V3 record ... first time around, check to see if it
 490      * really IS a V3 record.  Handle SSL V2 clients which can talk V3.0,
 491      * as well as real V3 record format; otherwise report an error.
 492      */
 493     void read(InputStream s, OutputStream o) throws IOException {
 494         if (isClosed) {
 495             return;
 496         }
 497 
 498         /*
 499          * For SSL it really _is_ an error if the other end went away
 500          * so ungracefully as to not shut down cleanly.
 501          */
 502         if(exlen < headerSize) {
 503             int really = readFully(s, buf, exlen, headerSize - exlen);
 504             if (really < 0) {
 505                 throw new EOFException("SSL peer shut down incorrectly");
 506             }
 507 
 508             pos = headerSize;
 509             count = headerSize;
 510             lastHashed = pos;
 511         }
 512 
 513         /*
 514          * The first record might use some other record marking convention,
 515          * typically SSL v2 header.  (PCT could also be detected here.)
 516          * This case is currently common -- Navigator 3.0 usually works
 517          * this way, as do IE 3.0 and other products.
 518          */
 519         if (!formatVerified) {
 520             formatVerified = true;
 521             /*
 522              * The first record must either be a handshake record or an
 523              * alert message. If it's not, it is either invalid or an
 524              * SSLv2 message.
 525              */
 526             if (buf[0] != ct_handshake && buf[0] != ct_alert) {
 527                 handleUnknownRecord(s, o);
 528             } else {
 529                 readV3Record(s, o);
 530             }
 531         } else { // formatVerified == true
 532             readV3Record(s, o);
 533         }
 534     }
 535 
 536     /**
 537      * Return true if the specified record protocol version is out of the
 538      * range of the possible supported versions.
 539      */
 540     static void checkRecordVersion(ProtocolVersion version,
 541             boolean allowSSL20Hello) throws SSLException {
 542         // Check if the record version is too old (currently not possible)
 543         // or if the major version does not match.
 544         //
 545         // The actual version negotiation is in the handshaker classes
 546         if ((version.v < ProtocolVersion.MIN.v) ||
 547             ((version.major & 0xFF) > (ProtocolVersion.MAX.major & 0xFF))) {
 548 
 549             // if it's not SSLv2, we're out of here.
 550             if (!allowSSL20Hello ||
 551                     (version.v != ProtocolVersion.SSL20Hello.v)) {
 552                 throw new SSLException("Unsupported record version " + version);
 553             }
 554         }
 555     }
 556 
 557     /**
 558      * Read a SSL/TLS record. Throw an IOException if the format is invalid.
 559      */
 560     private void readV3Record(InputStream s, OutputStream o)
 561             throws IOException {
 562         ProtocolVersion recordVersion = ProtocolVersion.valueOf(buf[1], buf[2]);
 563 
 564         // check the record version
 565         checkRecordVersion(recordVersion, false);
 566 
 567         /*
 568          * Get and check length, then the data.
 569          */
 570         int contentLen = ((buf[3] & 0x0ff) << 8) + (buf[4] & 0xff);
 571 
 572         /*
 573          * Check for upper bound.
 574          */
 575         if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) {
 576             throw new SSLProtocolException("Bad InputRecord size"
 577                 + ", count = " + contentLen
 578                 + ", buf.length = " + buf.length);
 579         }
 580 
 581         /*
 582          * Grow "buf" if needed. Since buf is maxRecordSize by default,
 583          * this only occurs when we receive records which violate the
 584          * SSL specification. This is a workaround for a Microsoft SSL bug.
 585          */
 586         if (contentLen > buf.length - headerSize) {
 587             byte[] newbuf = new byte[contentLen + headerSize];
 588             System.arraycopy(buf, 0, newbuf, 0, headerSize);
 589             buf = newbuf;
 590         }
 591 
 592         if (exlen < contentLen + headerSize) {
 593             int really = readFully(
 594                 s, buf, exlen, contentLen + headerSize - exlen);
 595             if (really < 0) {
 596                 throw new SSLException("SSL peer shut down incorrectly");
 597             }
 598         }
 599 
 600         // now we've got a complete record.
 601         count = contentLen + headerSize;
 602         exlen = 0;
 603 
 604         if (debug != null && Debug.isOn("record")) {
 605             if (count < 0 || count > (maxRecordSize - headerSize)) {
 606                 System.out.println(Thread.currentThread().getName()
 607                     + ", Bad InputRecord size" + ", count = " + count);
 608             }
 609             System.out.println(Thread.currentThread().getName()
 610                 + ", READ: " + recordVersion + " "
 611                 + contentName(contentType()) + ", length = " + available());
 612         }
 613         /*
 614          * then caller decrypts, verifies, and uncompresses
 615          */
 616     }
 617 
 618     /**
 619      * Deal with unknown records. Called if the first data we read on this
 620      * connection does not look like an SSL/TLS record. It could a SSLv2
 621      * message, or just garbage.
 622      */
 623     private void handleUnknownRecord(InputStream s, OutputStream o)
 624             throws IOException {
 625         /*
 626          * No?  Oh well; does it look like a V2 "ClientHello"?
 627          * That'd be an unpadded handshake message; we don't
 628          * bother checking length just now.
 629          */
 630         if (((buf[0] & 0x080) != 0) && buf[2] == 1) {
 631             /*
 632              * if the user has disabled SSLv2Hello (using
 633              * setEnabledProtocol) then throw an
 634              * exception
 635              */
 636             if (helloVersion != ProtocolVersion.SSL20Hello) {
 637                 throw new SSLHandshakeException("SSLv2Hello is disabled");
 638             }
 639 
 640             ProtocolVersion recordVersion =
 641                                 ProtocolVersion.valueOf(buf[3], buf[4]);
 642 
 643             if (recordVersion == ProtocolVersion.SSL20Hello) {
 644                 /*
 645                  * Looks like a V2 client hello, but not one saying
 646                  * "let's talk SSLv3".  So we send an SSLv2 error
 647                  * message, one that's treated as fatal by clients.
 648                  * (Otherwise we'll hang.)
 649                  */
 650                 try {
 651                     writeBuffer(o, v2NoCipher, 0, v2NoCipher.length);
 652                 } catch (Exception e) {
 653                     /* NOTHING */
 654                 }
 655                 throw new SSLException("Unsupported SSL v2.0 ClientHello");
 656             }
 657 
 658             /*
 659              * If we can map this into a V3 ClientHello, read and
 660              * hash the rest of the V2 handshake, turn it into a
 661              * V3 ClientHello message, and pass it up.
 662              */
 663             int len = ((buf[0] & 0x7f) << 8) +
 664                 (buf[1] & 0xff) - 3;
 665             if (v2Buf == null) {
 666                 v2Buf = new byte[len];
 667             }
 668             if (exlen < len + headerSize) {
 669                 int really = readFully(
 670                         s, v2Buf, exlen - headerSize, len + headerSize - exlen);
 671                 if (really < 0) {
 672                     throw new EOFException("SSL peer shut down incorrectly");
 673                 }
 674             }
 675 
 676             // now we've got a complete record.
 677             exlen = 0;
 678 
 679             hashInternal(buf, 2, 3);
 680             hashInternal(v2Buf, 0, len);
 681             V2toV3ClientHello(v2Buf);
 682             v2Buf = null;
 683             lastHashed = count;
 684 
 685             if (debug != null && Debug.isOn("record"))  {
 686                 System.out.println(
 687                     Thread.currentThread().getName()
 688                     + ", READ:  SSL v2, contentType = "
 689                     + contentName(contentType())
 690                     + ", translated length = " + available());
 691             }
 692             return;
 693 
 694         } else {
 695             /*
 696              * Does it look like a V2 "ServerHello"?
 697              */
 698             if (((buf [0] & 0x080) != 0) && buf [2] == 4) {
 699                 throw new SSLException(
 700                     "SSL V2.0 servers are not supported.");
 701             }
 702 
 703             /*
 704              * If this is a V2 NoCipher message then this means
 705              * the other server doesn't support V3. Otherwise, we just
 706              * don't understand what it's saying.
 707              */
 708             for (int i = 0; i < v2NoCipher.length; i++) {
 709                 if (buf[i] != v2NoCipher[i]) {
 710                     throw new SSLException(
 711                         "Unrecognized SSL message, plaintext connection?");
 712                 }
 713             }
 714 
 715             throw new SSLException("SSL V2.0 servers are not supported.");
 716         }
 717     }
 718 
 719     /*
 720      * Actually do the write here.  For SSLEngine's HS data,
 721      * we'll override this method and let it take the appropriate
 722      * action.
 723      */
 724     void writeBuffer(OutputStream s, byte [] buf, int off, int len)
 725             throws IOException {
 726         s.write(buf, 0, len);
 727         s.flush();
 728     }
 729 
 730     /*
 731      * Support "old" clients which are capable of SSL V3.0 protocol ... for
 732      * example, Navigator 3.0 clients.  The V2 message is in the header and
 733      * the bytes passed as parameter.  This routine translates the V2 message
 734      * into an equivalent V3 one.
 735      */
 736     private void V2toV3ClientHello(byte v2Msg []) throws SSLException
 737     {
 738         int i;
 739 
 740         /*
 741          * Build the first part of the V3 record header from the V2 one
 742          * that's now buffered up.  (Lengths are fixed up later).
 743          */
 744         buf [0] = ct_handshake;
 745         buf [1] = buf [3];      // V3.x
 746         buf[2] = buf[4];
 747         // header [3..4] for handshake message length
 748         // count = 5;
 749 
 750         /*
 751          * Store the generic V3 handshake header:  4 bytes
 752          */
 753         buf [5] = 1;    // HandshakeMessage.ht_client_hello
 754         // buf [6..8] for length of ClientHello (int24)
 755         // count += 4;
 756 
 757         /*
 758          * ClientHello header starts with SSL version
 759          */
 760         buf [9] = buf [1];
 761         buf [10] = buf [2];
 762         // count += 2;
 763         count = 11;
 764 
 765         /*
 766          * Start parsing the V2 message ...
 767          */
 768         int      cipherSpecLen, sessionIdLen, nonceLen;
 769 
 770         cipherSpecLen = ((v2Msg [0] & 0xff) << 8) + (v2Msg [1] & 0xff);
 771         sessionIdLen  = ((v2Msg [2] & 0xff) << 8) + (v2Msg [3] & 0xff);
 772         nonceLen   = ((v2Msg [4] & 0xff) << 8) + (v2Msg [5] & 0xff);
 773 
 774         /*
 775          * Copy Random value/nonce ... if less than the 32 bytes of
 776          * a V3 "Random", right justify and zero pad to the left.  Else
 777          * just take the last 32 bytes.
 778          */
 779         int      offset = 6 + cipherSpecLen + sessionIdLen;
 780 
 781         if (nonceLen < 32) {
 782             for (i = 0; i < (32 - nonceLen); i++)
 783                 buf [count++] = 0;
 784             System.arraycopy(v2Msg, offset, buf, count, nonceLen);
 785             count += nonceLen;
 786         } else {
 787             System.arraycopy(v2Msg, offset + (nonceLen - 32),
 788                     buf, count, 32);
 789             count += 32;
 790         }
 791 
 792         /*
 793          * Copy Session ID (only one byte length!)
 794          */
 795         offset -= sessionIdLen;
 796         buf [count++] = (byte) sessionIdLen;
 797 
 798         System.arraycopy(v2Msg, offset, buf, count, sessionIdLen);
 799         count += sessionIdLen;
 800 
 801         /*
 802          * Copy and translate cipher suites ... V2 specs with first byte zero
 803          * are really V3 specs (in the last 2 bytes), just copy those and drop
 804          * the other ones.  Preference order remains unchanged.
 805          *
 806          * Example:  Netscape Navigator 3.0 (exportable) says:
 807          *
 808          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
 809          * 0/6,     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
 810          *
 811          * Microsoft Internet Explorer 3.0 (exportable) supports only
 812          *
 813          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
 814          */
 815         int j;
 816 
 817         offset -= cipherSpecLen;
 818         j = count + 2;
 819 
 820         for (i = 0; i < cipherSpecLen; i += 3) {
 821             if (v2Msg [offset + i] != 0)
 822                 continue;
 823             buf [j++] = v2Msg [offset + i + 1];
 824             buf [j++] = v2Msg [offset + i + 2];
 825         }
 826 
 827         j -= count + 2;
 828         buf [count++] = (byte) (j >>> 8);
 829         buf [count++] = (byte) j;
 830         count += j;
 831 
 832         /*
 833          * Append compression methods (default/null only)
 834          */
 835         buf [count++] = 1;
 836         buf [count++] = 0;      // Session.compression_null
 837 
 838         /*
 839          * Fill in lengths of the messages we synthesized (nested:
 840          * V3 handshake message within V3 record) and then return
 841          */
 842         buf [3] = (byte) (count - headerSize);
 843         buf [4] = (byte) ((count - headerSize) >>> 8);
 844 
 845         buf [headerSize + 1] = 0;
 846         buf [headerSize + 2] = (byte) (((count - headerSize) - 4) >>> 8);
 847         buf [headerSize + 3] = (byte) ((count - headerSize) - 4);
 848 
 849         pos = headerSize;
 850     }
 851 
 852     /**
 853      * Return a description for the given content type. This method should be
 854      * in Record, but since that is an interface this is not possible.
 855      * Called from InputRecord and OutputRecord.
 856      */
 857     static String contentName(int contentType) {
 858         switch (contentType) {
 859         case ct_change_cipher_spec:
 860             return "Change Cipher Spec";
 861         case ct_alert:
 862             return "Alert";
 863         case ct_handshake:
 864             return "Handshake";
 865         case ct_application_data:
 866             return "Application Data";
 867         default:
 868             return "contentType = " + contentType;
 869         }
 870     }
 871 
 872 }



   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.*;
  31 
  32 import javax.crypto.BadPaddingException;
  33 
  34 import javax.net.ssl.*;
  35 
  36 import sun.misc.HexDumpEncoder;
  37 
  38 
  39 /**
  40  * {@code InputRecord} takes care of the management of SSL/TLS/DTLS input
  41  * records, including buffering, decryption, handshake messages marshal, etc.


  42  *








  43  * @author David Brownell
  44  */
  45 class InputRecord implements Record, Closeable {
  46 
  47     /* Class and subclass dynamic debugging support */
  48     static final Debug debug = Debug.getInstance("ssl");



  49 
  50     Authenticator       readAuthenticator;
  51     CipherBox           readCipher;
  52 
  53     HandshakeHash       handshakeHash;
  54     boolean             isClosed;
  55 
  56     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
  57     // and the first message we read is a ClientHello in V2 format, we convert
  58     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
  59     ProtocolVersion     helloVersion;
  60 
  61     // fragment size
  62     int                 fragmentSize;
  63 
  64     InputRecord() {
  65         this.readCipher = CipherBox.NULL;
  66         this.readAuthenticator = null;      // Please override this assignment.
  67         this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
  68         this.fragmentSize = Record.maxDataSize;
  69     }
  70 
  71     void setHelloVersion(ProtocolVersion helloVersion) {
  72         this.helloVersion = helloVersion;
  73     }
  74 
  75     ProtocolVersion getHelloVersion() {
  76         return helloVersion;
  77     }
  78 
  79     /*
  80      * Set instance for the computation of handshake hashes.

  81      *
  82      * For handshaking, we need to be able to hash every byte above the
  83      * record marking layer.  This is where we're guaranteed to see those
  84      * bytes, so this is where we can hash them ... especially in the
  85      * case of hashing the initial V2 message!
  86      */
  87     void setHandshakeHash(HandshakeHash handshakeHash) {
  88         if (handshakeHash != null) {
  89             byte[] reserved = null;
  90             if (this.handshakeHash != null) {
  91                 reserved = this.handshakeHash.getAllHandshakeMessages();
  92             }
  93             if ((reserved != null) && (reserved.length != 0)) {
  94                 handshakeHash.update(reserved, 0, reserved.length);
  95 
  96                if (debug != null && Debug.isOn("data")) {
  97                     Debug.printHex(
  98                         "[reserved] handshake hash: len = " + reserved.length,
  99                         reserved);
 100                }
 101             }
 102         }
 103 
 104         this.handshakeHash = handshakeHash;
 105     }
 106 
 107     boolean seqNumIsHuge() {
 108         return (readAuthenticator != null) &&
 109                         readAuthenticator.seqNumIsHuge();
 110     }
 111 
 112     boolean isEmpty() {
 113         return false;
 114     }
 115 
 116     // apply to DTLS SSLEngine
 117     void expectingFinishFlight() {
 118         // blank
 119     }
 120 
 121     /**
 122      * Prevent any more data from being read into this record,
 123      * and flag the record as holding no data.
 124      */
 125     @Override
 126     synchronized public void close() throws IOException {
 127         if (!isClosed) {
 128             isClosed = true;
 129             readCipher.dispose();
 130         }
 131     }
 132 
 133     // apply to SSLSocket and SSLEngine
 134     void changeReadCiphers(
 135             Authenticator readAuthenticator, CipherBox readCipher) {
 136 
 137         /*
 138          * Dispose of any intermediate state in the underlying cipher.
 139          * For PKCS11 ciphers, this will release any attached sessions,
 140          * and thus make finalization faster.
 141          *
 142          * Since MAC's doFinal() is called for every SSL/TLS packet, it's
 143          * not necessary to do the same with MAC's.
 144          */
 145         readCipher.dispose();
 146 
 147         this.readAuthenticator = readAuthenticator;
 148         this.readCipher = readCipher;
 149     }
 150 
 151     // change fragment size
 152     void changeFragmentSize(int fragmentSize) {
 153         this.fragmentSize = fragmentSize;
 154     }
 155 
 156     /*
 157      * Check if there is enough inbound data in the ByteBuffer to make
 158      * a inbound packet.
 159      *
 160      * @return -1 if there are not enough bytes to tell (small header),



 161      */
 162     // apply to SSLEngine only
 163     int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
 164         throw new UnsupportedOperationException();





 165     }
 166 
 167     // apply to SSLSocket only
 168     int bytesInCompletePacket(InputStream is) throws IOException {
 169         throw new UnsupportedOperationException();
 170     }
 171 
 172     /**
 173      * Return true if the specified record protocol version is out of the
 174      * range of the possible supported versions.
 175      */
 176     void checkRecordVersion(ProtocolVersion version,
 177             boolean allowSSL20Hello) throws SSLException {
 178         // blank
 179     }
 180 
 181     // apply to DTLS SSLEngine only
 182     Plaintext acquirePlaintext()
 183             throws IOException, BadPaddingException {
 184         throw new UnsupportedOperationException();
 185     }
 186 
 187     // read, decrypt and decompress the network record.
 188     //
 189     // apply to SSLEngine only
 190     Plaintext decode(ByteBuffer netData)
 191             throws IOException, BadPaddingException {
 192         throw new UnsupportedOperationException();
 193     }
 194 
 195     // apply to SSLSocket only
 196     Plaintext decode(InputStream is, ByteBuffer destination)
 197             throws IOException, BadPaddingException {
 198         throw new UnsupportedOperationException();
 199     }
 200 
 201     // apply to SSLSocket only
 202     void setDeliverStream(OutputStream outputStream) {
 203         throw new UnsupportedOperationException();
 204     }
 205 
 206     // calculate plaintext fragment size
 207     //
 208     // apply to SSLEngine only
 209     int estimateFragmentSize(int packetSize) {
 210         throw new UnsupportedOperationException();
 211     }
 212 
 213     //
 214     // shared helpers
 215     //
 216 
 217     // Not apply to DTLS
 218     static ByteBuffer convertToClientHello(ByteBuffer packet) {
 219 
 220         int srcPos = packet.position();
 221         int srcLim = packet.limit();
 222 
 223         byte firstByte = packet.get();
 224         byte secondByte = packet.get();
 225         int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2;
 226 
 227         packet.position(srcPos + 3);        // the V2ClientHello record header
 228 
 229         byte majorVersion = packet.get();
 230         byte minorVersion = packet.get();
 231 
 232         int cipherSpecLen = ((packet.get() & 0xFF) << 8) +
 233                              (packet.get() & 0xFF);
 234         int sessionIdLen  = ((packet.get() & 0xFF) << 8) +
 235                              (packet.get() & 0xFF);
 236         int nonceLen      = ((packet.get() & 0xFF) << 8) +
 237                              (packet.get() & 0xFF);
 238 
 239         // Required space for the target SSLv3 ClientHello message.
 240         //  5: record header size
 241         //  4: handshake header size
 242         //  2: ClientHello.client_version
 243         // 32: ClientHello.random
 244         //  1: length byte of ClientHello.session_id
 245         //  2: empty ClientHello.compression_methods
 246         int requiredSize = 46 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 );
 247         byte[] converted = new byte[requiredSize];
 248 
 249         /*
 250          * Build the first part of the V3 record header from the V2 one
 251          * that's now buffered up.  (Lengths are fixed up later).
 252          */
 253         // Note: need not to set the header actually.
 254         converted[0] = ct_handshake;
 255         converted[1] = majorVersion;
 256         converted[2] = minorVersion;
 257         // header [3..4] for handshake message length
 258         // required size is 5;
 259 
 260         /*
 261          * Store the generic V3 handshake header:  4 bytes
 262          */
 263         converted[5] = 1;    // HandshakeMessage.ht_client_hello
 264         // buf [6..8] for length of ClientHello (int24)
 265         // required size += 4;
 266 
 267         /*
 268          * ClientHello header starts with SSL version
 269          */
 270         converted[9] = majorVersion;
 271         converted[10] = minorVersion;
 272         // required size += 2;
 273         int pointer = 11;
 274 
 275         /*
 276          * Copy Random value/nonce ... if less than the 32 bytes of
 277          * a V3 "Random", right justify and zero pad to the left.  Else
 278          * just take the last 32 bytes.
 279          */
 280         int offset = srcPos + 11 + cipherSpecLen + sessionIdLen;
 281 
 282         if (nonceLen < 32) {
 283             for (int i = 0; i < (32 - nonceLen); i++) {
 284                 converted[pointer++] = 0;
 285             }
 286             packet.position(offset);
 287             packet.get(converted, pointer, nonceLen);
 288 
 289             pointer += nonceLen;
 290         } else {
 291             packet.position(offset + nonceLen - 32);
 292             packet.get(converted, pointer, 32);
 293 
 294             pointer += 32;
 295         }
 296 
 297         /*
 298          * Copy session ID (only one byte length!)
 299          */
 300         offset -= sessionIdLen;
 301         converted[pointer++] = (byte)(sessionIdLen & 0xFF);
 302         packet.position(offset);
 303         packet.get(converted, pointer, sessionIdLen);
 304 
 305         /*
 306          * Copy and translate cipher suites ... V2 specs with first byte zero
 307          * are really V3 specs (in the last 2 bytes), just copy those and drop
 308          * the other ones.  Preference order remains unchanged.
 309          *
 310          * Example:  Netscape Navigator 3.0 (exportable) says:
 311          *
 312          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
 313          * 0/6,     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
 314          *
 315          * Microsoft Internet Explorer 3.0 (exportable) supports only
 316          *
 317          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
 318          */
 319         int j;
 320 
 321         offset -= cipherSpecLen;
 322         packet.position(offset);
 323 
 324         j = pointer + 2;
 325         for (int i = 0; i < cipherSpecLen; i += 3) {
 326             if (packet.get() != 0) {
 327                 // Ignore version 2.0 specifix cipher suite.  Clients
 328                 // should also include the version 3.0 equivalent in
 329                 // the V2ClientHello message.
 330                 packet.get();           // ignore the 2nd byte
 331                 packet.get();           // ignore the 3rd byte
 332                 continue;
 333             }
 334 
 335             converted[j++] = packet.get();
 336             converted[j++] = packet.get();
 337         }
 338 
 339         j -= pointer + 2;
 340         converted[pointer++] = (byte)((j >>> 8) & 0xFF);
 341         converted[pointer++] = (byte)(j & 0xFF);
 342         pointer += j;
 343 
 344         /*
 345          * Append compression methods (default/null only)



 346          */
 347         converted[pointer++] = 1;
 348         converted[pointer++] = 0;      // Session.compression_null
 349 
 350         /*
 351          * Fill in lengths of the messages we synthesized (nested:
 352          * V3 handshake message within V3 record).
 353          */
 354         // Note: need not to set the header actually.
 355         int fragLen = pointer - 5;                      // TLSPlaintext.length
 356         converted[3] = (byte)((fragLen >>> 8) & 0xFF);
 357         converted[4] = (byte)(fragLen & 0xFF);
 358 
 359         /*
 360          * Handshake.length, length of ClientHello message
 361          */
 362         fragLen = pointer - 9;                          // Handshake.length
 363         converted[6] = (byte)((fragLen >>> 16) & 0xFF);
 364         converted[7] = (byte)((fragLen >>> 8) & 0xFF);
 365         converted[8] = (byte)(fragLen & 0xFF);
 366 
 367         // consume the full record
 368         packet.position(srcPos + recordLen);
 369         
 370         // Need no header bytes.
 371         return ByteBuffer.wrap(converted, 5, pointer - 5);  // 5: header size
 372     }
 373 
 374     static ByteBuffer decrypt(Authenticator authenticator, CipherBox box,
 375             byte contentType, ByteBuffer bb) throws BadPaddingException {
 376 
 377         return decrypt(authenticator, box, contentType, bb, null);
 378     }
 379 
 380     static ByteBuffer decrypt(Authenticator authenticator,
 381             CipherBox box, byte contentType, ByteBuffer bb,
 382             byte[] sequence) throws BadPaddingException {
 383 
 384         BadPaddingException reservedBPE = null;
 385         int tagLen =
 386             (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
 387         int cipheredLength = bb.remaining();
 388         int srcPos = bb.position();
 389         if (!box.isNullCipher()) {
 390             try {
 391                 // apply explicit nonce for AEAD/CBC cipher suites if needed
 392                 int nonceSize = box.applyExplicitNonce(
 393                         authenticator, contentType, bb, sequence);


 394 
 395                 // decrypt the content

 396                 if (box.isAEADMode()) {
 397                     // DON'T decrypt the nonce_explicit for AEAD mode
 398                     bb.position(srcPos + nonceSize);
 399                 }   // The explicit IV for CBC mode can be decrypted.
 400 
 401                 // Note that the CipherBox.decrypt() does not change
 402                 // the capacity of the buffer.
 403                 box.decrypt(bb, tagLen);
 404                 // We don't actually remove the nonce.
 405                 bb.position(srcPos + nonceSize);

 406             } catch (BadPaddingException bpe) {
 407                 // RFC 2246 states that decryption_failed should be used
 408                 // for this purpose. However, that allows certain attacks,
 409                 // so we just send bad record MAC. We also need to make
 410                 // sure to always check the MAC to avoid a timing attack
 411                 // for the same issue. See paper by Vaudenay et al and the
 412                 // update in RFC 4346/5246.
 413                 //
 414                 // Failover to message authentication code checking.
 415                 reservedBPE = bpe;
 416             }
 417         }
 418 
 419         // Requires message authentication code for null, stream and block
 420         // cipher suites.
 421         if ((authenticator instanceof MAC) && (tagLen != 0)) {
 422             MAC signer = (MAC)authenticator;
 423             int contentLen = bb.remaining() - tagLen;

 424 
 425             // Note that although it is not necessary, we run the same MAC
 426             // computation and comparison on the payload for both stream
 427             // cipher and CBC block cipher.
 428             if (contentLen < 0) {
 429                 // negative data length, something is wrong
 430                 if (reservedBPE == null) {
 431                     reservedBPE = new BadPaddingException("bad record");
 432                 }
 433 
 434                 // set offset of the dummy MAC
 435                 contentLen = cipheredLength - tagLen;
 436                 bb.limit(srcPos + cipheredLength);
 437             }
 438 






 439             // Run MAC computation and comparison on the payload.
 440             //
 441             // MAC data would be stripped off during the check.
 442             if (checkMacTags(contentType, bb, signer, sequence, false)) {
 443                 if (reservedBPE == null) {
 444                     reservedBPE = new BadPaddingException("bad record MAC");
 445                 }
 446             }
 447 
 448             // Run MAC computation and comparison on the remainder.
 449             //
 450             // It is only necessary for CBC block cipher.  It is used to get a
 451             // constant time of MAC computation and comparison on each record.
 452             if (box.isCBCMode()) {
 453                 int remainingLen = calculateRemainingLen(
 454                                         signer, cipheredLength, contentLen);
 455                 
 456                 // NOTE: remainingLen may be bigger (less than 1 block of the
 457                 // hash algorithm of the MAC) than the cipheredLength.
 458                 //
 459                 // Is it possible to use a static buffer, rather than allocate
 460                 // it dynamically?
 461                 remainingLen += signer.MAClen();
 462                 ByteBuffer temporary = ByteBuffer.allocate(remainingLen);



 463 
 464                 // Won't need to worry about the result on the remainder. And
 465                 // then we won't need to worry about what's actual data to
 466                 // check MAC tag on.  We start the check from the header of the
 467                 // buffer so that we don't need to construct a new byte buffer.
 468                 checkMacTags(contentType, temporary, signer, sequence, true);
 469             }
 470         }
 471 
 472         // Is it a failover?
 473         if (reservedBPE != null) {
 474             throw reservedBPE;
 475         }
 476 
 477         return bb.slice();
 478     }
 479 
 480     /*
 481      * Run MAC computation and comparison
 482      *
 483      */
 484     private static boolean checkMacTags(byte contentType, ByteBuffer bb,
 485             MAC signer, byte[] sequence, boolean isSimulated) {
 486 
 487         int tagLen = signer.MAClen();
 488         int position = bb.position();
 489         int lim = bb.limit();
 490         int macOffset = lim - tagLen;
 491 
 492         bb.limit(macOffset);
 493         byte[] hash = signer.compute(contentType, bb, sequence, isSimulated);
 494         if (hash == null || tagLen != hash.length) {
 495             // Something is wrong with MAC implementation.
 496             throw new RuntimeException("Internal MAC error");
 497         }
 498 
 499         bb.position(macOffset);
 500         bb.limit(lim);
 501         try {
 502             int[] results = compareMacTags(bb, hash);
 503             return (results[0] != 0);
 504         } finally {
 505             // reset to the data
 506             bb.position(position);
 507             bb.limit(macOffset);
 508         }
 509     }
 510 
 511     /*
 512      * A constant-time comparison of the MAC tags.
 513      *
 514      * Please DON'T change the content of the ByteBuffer parameter!
 515      */
 516     private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
 517 
 518         // An array of hits is used to prevent Hotspot optimization for
 519         // the purpose of a constant-time check.
 520         int[] results = {0, 0};     // {missed #, matched #}
 521 
 522         // The caller ensures there are enough bytes available in the buffer.
 523         // So we won't need to check the remaining of the buffer.
 524         for (int i = 0; i < tag.length; i++) {
 525             if (bb.get() != tag[i]) {
 526                 results[0]++;       // mismatched bytes
 527             } else {
 528                 results[1]++;       // matched bytes
 529             }
 530         }
 531 
 532         return results;
 533     }
 534 
 535     /*
 536      * Run MAC computation and comparison
 537      *
 538      * Please DON'T change the content of the byte buffer parameter!
 539      */
 540     private static boolean checkMacTags(byte contentType, byte[] buffer,
 541             int offset, int contentLen, MAC signer, boolean isSimulated) {
 542 
 543         int tagLen = signer.MAClen();
 544         byte[] hash = signer.compute(
 545                 contentType, buffer, offset, contentLen, isSimulated);
 546         if (hash == null || tagLen != hash.length) {
 547             // Something is wrong with MAC implementation.
 548             throw new RuntimeException("Internal MAC error");
 549         }
 550 
 551         int[] results = compareMacTags(buffer, offset + contentLen, hash);
 552         return (results[0] != 0);
 553     }
 554 
 555     /*
 556      * A constant-time comparison of the MAC tags.
 557      *
 558      * Please DON'T change the content of the byte buffer parameter!
 559      */
 560     private static int[] compareMacTags(


 566 
 567         // The caller ensures there are enough bytes available in the buffer.
 568         // So we won't need to check the length of the buffer.
 569         for (int i = 0; i < tag.length; i++) {
 570             if (buffer[offset + i] != tag[i]) {
 571                 results[0]++;       // mismatched bytes
 572             } else {
 573                 results[1]++;       // matched bytes
 574             }
 575         }
 576 
 577         return results;
 578     }
 579 
 580     /*
 581      * Calculate the length of a dummy buffer to run MAC computation
 582      * and comparison on the remainder.
 583      *
 584      * The caller MUST ensure that the fullLen is not less than usedLen.
 585      */
 586     private static int calculateRemainingLen(
 587             MAC signer, int fullLen, int usedLen) {
 588 
 589         int blockLen = signer.hashBlockLen();
 590         int minimalPaddingLen = signer.minimalPaddingLen();
 591 
 592         // (blockLen - minimalPaddingLen) is the maximum message size of
 593         // the last block of hash function operation. See FIPS 180-4, or
 594         // MD5 specification.
 595         fullLen += 13 - (blockLen - minimalPaddingLen);
 596         usedLen += 13 - (blockLen - minimalPaddingLen);
 597 
 598         // Note: fullLen is always not less than usedLen, and blockLen
 599         // is always bigger than minimalPaddingLen, so we don't worry
 600         // about negative values. 0x01 is added to the result to ensure
 601         // that the return value is positive.  The extra one byte does
 602         // not impact the overall MAC compression function evaluations.
 603         return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
 604                 Math.ceil(usedLen/(1.0d * blockLen))) * blockLen;
 605     }

































































































































































































































































































































































































































































































































































 606 }
 607