jdk/src/java.base/share/classes/sun/security/ssl/InputRecord.java
changeset 30904 ec0224270f90
parent 25859 3317bb8137f4
child 32649 2ee9017c7597
equal deleted inserted replaced
30903:0c7d705209c6 30904:ec0224270f90
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    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
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 
    25 
    26 
       
    27 package sun.security.ssl;
    26 package sun.security.ssl;
    28 
    27 
    29 import java.io.*;
    28 import java.io.*;
    30 import java.nio.*;
    29 import java.nio.*;
       
    30 import java.util.*;
    31 
    31 
    32 import javax.crypto.BadPaddingException;
    32 import javax.crypto.BadPaddingException;
    33 
    33 
    34 import javax.net.ssl.*;
    34 import javax.net.ssl.*;
    35 
    35 
    36 import sun.misc.HexDumpEncoder;
    36 import sun.misc.HexDumpEncoder;
    37 
    37 
    38 
    38 
    39 /**
    39 /**
    40  * SSL 3.0 records, as pulled off a TCP stream.  Input records are
    40  * {@code InputRecord} takes care of the management of SSL/TLS/DTLS input
    41  * basically buffers tied to a particular input stream ... a layer
    41  * records, including buffering, decryption, handshake messages marshal, etc.
    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  *
    42  *
    53  * @author David Brownell
    43  * @author David Brownell
    54  */
    44  */
    55 class InputRecord extends ByteArrayInputStream implements Record {
    45 class InputRecord implements Record, Closeable {
    56 
    46 
    57     private HandshakeHash       handshakeHash;
    47     /* Class and subclass dynamic debugging support */
    58     private int                 lastHashed;
    48     static final Debug debug = Debug.getInstance("ssl");
    59     boolean                     formatVerified = true;  // SSLv2 ruled out?
    49 
    60     private boolean             isClosed;
    50     Authenticator       readAuthenticator;
    61     private boolean             appDataValid;
    51     CipherBox           readCipher;
       
    52 
       
    53     HandshakeHash       handshakeHash;
       
    54     boolean             isClosed;
    62 
    55 
    63     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
    56     // 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
    57     // 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.
    58     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
    66     private ProtocolVersion     helloVersion;
    59     ProtocolVersion     helloVersion;
    67 
    60 
    68     /* Class and subclass dynamic debugging support */
    61     // fragment size
    69     static final Debug debug = Debug.getInstance("ssl");
    62     int                 fragmentSize;
    70 
    63 
    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() {
    64     InputRecord() {
    93         super(new byte[maxRecordSize]);
    65         this.readCipher = CipherBox.NULL;
    94         setHelloVersion(ProtocolVersion.DEFAULT_HELLO);
    66         this.readAuthenticator = null;      // Please override this assignment.
    95         pos = headerSize;
    67         this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
    96         count = headerSize;
    68         this.fragmentSize = Record.maxDataSize;
    97         lastHashed = count;
       
    98         exlen = 0;
       
    99         v2Buf = null;
       
   100     }
    69     }
   101 
    70 
   102     void setHelloVersion(ProtocolVersion helloVersion) {
    71     void setHelloVersion(ProtocolVersion helloVersion) {
   103         this.helloVersion = helloVersion;
    72         this.helloVersion = helloVersion;
   104     }
    73     }
   106     ProtocolVersion getHelloVersion() {
    75     ProtocolVersion getHelloVersion() {
   107         return helloVersion;
    76         return helloVersion;
   108     }
    77     }
   109 
    78 
   110     /*
    79     /*
   111      * Enable format checks if initial handshaking hasn't completed
    80      * Set instance for the computation of handshake hashes.
   112      */
    81      *
   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
    82      * 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
    83      * 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
    84      * bytes, so this is where we can hash them ... especially in the
   137      * case of hashing the initial V2 message!
    85      * case of hashing the initial V2 message!
   138      */
    86      */
   139     void setHandshakeHash(HandshakeHash handshakeHash) {
    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 
   140         this.handshakeHash = handshakeHash;
   104         this.handshakeHash = handshakeHash;
   141     }
   105     }
   142 
   106 
   143     HandshakeHash getHandshakeHash() {
   107     boolean seqNumIsHuge() {
   144         return handshakeHash;
   108         return (readAuthenticator != null) &&
   145     }
   109                         readAuthenticator.seqNumIsHuge();
   146 
   110     }
   147     void decrypt(Authenticator authenticator,
   111 
   148             CipherBox box) throws BadPaddingException {
   112     boolean isEmpty() {
   149         BadPaddingException reservedBPE = null;
   113         return false;
   150         int tagLen =
   114     }
   151             (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
   115 
   152         int cipheredLength = count - headerSize;
   116     // apply to DTLS SSLEngine
   153 
   117     void expectingFinishFlight() {
   154         if (!box.isNullCipher()) {
   118         // blank
   155             try {
   119     }
   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(
       
   282             byte[] buffer, int offset, byte[] tag) {
       
   283 
       
   284         // An array of hits is used to prevent Hotspot optimization for
       
   285         // the purpose of a constant-time check.
       
   286         int[] results = {0, 0};    // {missed #, matched #}
       
   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 
   120 
   436     /**
   121     /**
   437      * Prevent any more data from being read into this record,
   122      * Prevent any more data from being read into this record,
   438      * and flag the record as holding no data.
   123      * and flag the record as holding no data.
   439      */
   124      */
   440     @Override
   125     @Override
   441     public void close() {
   126     synchronized public void close() throws IOException {
   442         appDataValid = false;
   127         if (!isClosed) {
   443         isClosed = true;
   128             isClosed = true;
   444         mark = 0;
   129             readCipher.dispose();
   445         pos = 0;
   130         }
   446         count = 0;
   131     }
   447     }
   132 
   448 
   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     }
   449 
   155 
   450     /*
   156     /*
   451      * We may need to send this SSL v2 "No Cipher" message back, if we
   157      * Check if there is enough inbound data in the ByteBuffer to make
   452      * are faced with an SSLv2 "hello" that's not saying "I talk v3".
   158      * a inbound packet.
   453      * It's the only one documented in the V2 spec as a fatal error.
   159      *
   454      */
   160      * @return -1 if there are not enough bytes to tell (small header),
   455     private static final byte[] v2NoCipher = {
   161      */
   456         (byte)0x80, (byte)0x03, // unpadded 3 byte record
   162     // apply to SSLEngine only
   457         (byte)0x00,             // ... error message
   163     int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
   458         (byte)0x00, (byte)0x01  // ... NO_CIPHER error
   164         throw new UnsupportedOperationException();
   459     };
   165     }
   460 
   166 
   461     private int readFully(InputStream s, byte b[], int off, int len)
   167     // apply to SSLSocket only
   462             throws IOException {
   168     int bytesInCompletePacket(InputStream is) throws IOException {
   463         int n = 0;
   169         throw new UnsupportedOperationException();
   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     }
   170     }
   535 
   171 
   536     /**
   172     /**
   537      * Return true if the specified record protocol version is out of the
   173      * Return true if the specified record protocol version is out of the
   538      * range of the possible supported versions.
   174      * range of the possible supported versions.
   539      */
   175      */
   540     static void checkRecordVersion(ProtocolVersion version,
   176     void checkRecordVersion(ProtocolVersion version,
   541             boolean allowSSL20Hello) throws SSLException {
   177             boolean allowSSL20Hello) throws SSLException {
   542         // Check if the record version is too old (currently not possible)
   178         // blank
   543         // or if the major version does not match.
   179     }
   544         //
   180 
   545         // The actual version negotiation is in the handshaker classes
   181     // apply to DTLS SSLEngine only
   546         if ((version.v < ProtocolVersion.MIN.v) ||
   182     Plaintext acquirePlaintext()
   547             ((version.major & 0xFF) > (ProtocolVersion.MAX.major & 0xFF))) {
   183             throws IOException, BadPaddingException {
   548 
   184         throw new UnsupportedOperationException();
   549             // if it's not SSLv2, we're out of here.
   185     }
   550             if (!allowSSL20Hello ||
   186 
   551                     (version.v != ProtocolVersion.SSL20Hello.v)) {
   187     // read, decrypt and decompress the network record.
   552                 throw new SSLException("Unsupported record version " + version);
   188     //
   553             }
   189     // apply to SSLEngine only
   554         }
   190     Plaintext decode(ByteBuffer netData)
   555     }
   191             throws IOException, BadPaddingException {
   556 
   192         throw new UnsupportedOperationException();
   557     /**
   193     }
   558      * Read a SSL/TLS record. Throw an IOException if the format is invalid.
   194 
   559      */
   195     // apply to SSLSocket only
   560     private void readV3Record(InputStream s, OutputStream o)
   196     Plaintext decode(InputStream is, ByteBuffer destination)
   561             throws IOException {
   197             throws IOException, BadPaddingException {
   562         ProtocolVersion recordVersion = ProtocolVersion.valueOf(buf[1], buf[2]);
   198         throw new UnsupportedOperationException();
   563 
   199     }
   564         // check the record version
   200 
   565         checkRecordVersion(recordVersion, false);
   201     // apply to SSLSocket only
   566 
   202     void setDeliverStream(OutputStream outputStream) {
   567         /*
   203         throw new UnsupportedOperationException();
   568          * Get and check length, then the data.
   204     }
   569          */
   205 
   570         int contentLen = ((buf[3] & 0x0ff) << 8) + (buf[4] & 0xff);
   206     // calculate plaintext fragment size
   571 
   207     //
   572         /*
   208     // apply to SSLEngine only
   573          * Check for upper bound.
   209     int estimateFragmentSize(int packetSize) {
   574          */
   210         throw new UnsupportedOperationException();
   575         if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) {
   211     }
   576             throw new SSLProtocolException("Bad InputRecord size"
   212 
   577                 + ", count = " + contentLen
   213     //
   578                 + ", buf.length = " + buf.length);
   214     // shared helpers
   579         }
   215     //
   580 
   216 
   581         /*
   217     // Not apply to DTLS
   582          * Grow "buf" if needed. Since buf is maxRecordSize by default,
   218     static ByteBuffer convertToClientHello(ByteBuffer packet) {
   583          * this only occurs when we receive records which violate the
   219 
   584          * SSL specification. This is a workaround for a Microsoft SSL bug.
   220         int srcPos = packet.position();
   585          */
   221         int srcLim = packet.limit();
   586         if (contentLen > buf.length - headerSize) {
   222 
   587             byte[] newbuf = new byte[contentLen + headerSize];
   223         byte firstByte = packet.get();
   588             System.arraycopy(buf, 0, newbuf, 0, headerSize);
   224         byte secondByte = packet.get();
   589             buf = newbuf;
   225         int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2;
   590         }
   226 
   591 
   227         packet.position(srcPos + 3);        // the V2ClientHello record header
   592         if (exlen < contentLen + headerSize) {
   228 
   593             int really = readFully(
   229         byte majorVersion = packet.get();
   594                 s, buf, exlen, contentLen + headerSize - exlen);
   230         byte minorVersion = packet.get();
   595             if (really < 0) {
   231 
   596                 throw new SSLException("SSL peer shut down incorrectly");
   232         int cipherSpecLen = ((packet.get() & 0xFF) << 8) +
   597             }
   233                              (packet.get() & 0xFF);
   598         }
   234         int sessionIdLen  = ((packet.get() & 0xFF) << 8) +
   599 
   235                              (packet.get() & 0xFF);
   600         // now we've got a complete record.
   236         int nonceLen      = ((packet.get() & 0xFF) << 8) +
   601         count = contentLen + headerSize;
   237                              (packet.get() & 0xFF);
   602         exlen = 0;
   238 
   603 
   239         // Required space for the target SSLv3 ClientHello message.
   604         if (debug != null && Debug.isOn("record")) {
   240         //  5: record header size
   605             if (count < 0 || count > (maxRecordSize - headerSize)) {
   241         //  4: handshake header size
   606                 System.out.println(Thread.currentThread().getName()
   242         //  2: ClientHello.client_version
   607                     + ", Bad InputRecord size" + ", count = " + count);
   243         // 32: ClientHello.random
   608             }
   244         //  1: length byte of ClientHello.session_id
   609             System.out.println(Thread.currentThread().getName()
   245         //  2: empty ClientHello.compression_methods
   610                 + ", READ: " + recordVersion + " "
   246         int requiredSize = 46 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 );
   611                 + contentName(contentType()) + ", length = " + available());
   247         byte[] converted = new byte[requiredSize];
   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 
   248 
   740         /*
   249         /*
   741          * Build the first part of the V3 record header from the V2 one
   250          * Build the first part of the V3 record header from the V2 one
   742          * that's now buffered up.  (Lengths are fixed up later).
   251          * that's now buffered up.  (Lengths are fixed up later).
   743          */
   252          */
   744         buf [0] = ct_handshake;
   253         // Note: need not to set the header actually.
   745         buf [1] = buf [3];      // V3.x
   254         converted[0] = ct_handshake;
   746         buf[2] = buf[4];
   255         converted[1] = majorVersion;
       
   256         converted[2] = minorVersion;
   747         // header [3..4] for handshake message length
   257         // header [3..4] for handshake message length
   748         // count = 5;
   258         // required size is 5;
   749 
   259 
   750         /*
   260         /*
   751          * Store the generic V3 handshake header:  4 bytes
   261          * Store the generic V3 handshake header:  4 bytes
   752          */
   262          */
   753         buf [5] = 1;    // HandshakeMessage.ht_client_hello
   263         converted[5] = 1;    // HandshakeMessage.ht_client_hello
   754         // buf [6..8] for length of ClientHello (int24)
   264         // buf [6..8] for length of ClientHello (int24)
   755         // count += 4;
   265         // required size += 4;
   756 
   266 
   757         /*
   267         /*
   758          * ClientHello header starts with SSL version
   268          * ClientHello header starts with SSL version
   759          */
   269          */
   760         buf [9] = buf [1];
   270         converted[9] = majorVersion;
   761         buf [10] = buf [2];
   271         converted[10] = minorVersion;
   762         // count += 2;
   272         // required size += 2;
   763         count = 11;
   273         int pointer = 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 
   274 
   774         /*
   275         /*
   775          * Copy Random value/nonce ... if less than the 32 bytes of
   276          * Copy Random value/nonce ... if less than the 32 bytes of
   776          * a V3 "Random", right justify and zero pad to the left.  Else
   277          * a V3 "Random", right justify and zero pad to the left.  Else
   777          * just take the last 32 bytes.
   278          * just take the last 32 bytes.
   778          */
   279          */
   779         int      offset = 6 + cipherSpecLen + sessionIdLen;
   280         int offset = srcPos + 11 + cipherSpecLen + sessionIdLen;
   780 
   281 
   781         if (nonceLen < 32) {
   282         if (nonceLen < 32) {
   782             for (i = 0; i < (32 - nonceLen); i++)
   283             for (int i = 0; i < (32 - nonceLen); i++) {
   783                 buf [count++] = 0;
   284                 converted[pointer++] = 0;
   784             System.arraycopy(v2Msg, offset, buf, count, nonceLen);
   285             }
   785             count += nonceLen;
   286             packet.position(offset);
       
   287             packet.get(converted, pointer, nonceLen);
       
   288 
       
   289             pointer += nonceLen;
   786         } else {
   290         } else {
   787             System.arraycopy(v2Msg, offset + (nonceLen - 32),
   291             packet.position(offset + nonceLen - 32);
   788                     buf, count, 32);
   292             packet.get(converted, pointer, 32);
   789             count += 32;
   293 
   790         }
   294             pointer += 32;
   791 
   295         }
   792         /*
   296 
   793          * Copy Session ID (only one byte length!)
   297         /*
       
   298          * Copy session ID (only one byte length!)
   794          */
   299          */
   795         offset -= sessionIdLen;
   300         offset -= sessionIdLen;
   796         buf [count++] = (byte) sessionIdLen;
   301         converted[pointer++] = (byte)(sessionIdLen & 0xFF);
   797 
   302         packet.position(offset);
   798         System.arraycopy(v2Msg, offset, buf, count, sessionIdLen);
   303         packet.get(converted, pointer, sessionIdLen);
   799         count += sessionIdLen;
       
   800 
   304 
   801         /*
   305         /*
   802          * Copy and translate cipher suites ... V2 specs with first byte zero
   306          * 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
   307          * are really V3 specs (in the last 2 bytes), just copy those and drop
   804          * the other ones.  Preference order remains unchanged.
   308          * the other ones.  Preference order remains unchanged.
   813          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
   317          * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
   814          */
   318          */
   815         int j;
   319         int j;
   816 
   320 
   817         offset -= cipherSpecLen;
   321         offset -= cipherSpecLen;
   818         j = count + 2;
   322         packet.position(offset);
   819 
   323 
   820         for (i = 0; i < cipherSpecLen; i += 3) {
   324         j = pointer + 2;
   821             if (v2Msg [offset + i] != 0)
   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
   822                 continue;
   332                 continue;
   823             buf [j++] = v2Msg [offset + i + 1];
   333             }
   824             buf [j++] = v2Msg [offset + i + 2];
   334 
   825         }
   335             converted[j++] = packet.get();
   826 
   336             converted[j++] = packet.get();
   827         j -= count + 2;
   337         }
   828         buf [count++] = (byte) (j >>> 8);
   338 
   829         buf [count++] = (byte) j;
   339         j -= pointer + 2;
   830         count += j;
   340         converted[pointer++] = (byte)((j >>> 8) & 0xFF);
       
   341         converted[pointer++] = (byte)(j & 0xFF);
       
   342         pointer += j;
   831 
   343 
   832         /*
   344         /*
   833          * Append compression methods (default/null only)
   345          * Append compression methods (default/null only)
   834          */
   346          */
   835         buf [count++] = 1;
   347         converted[pointer++] = 1;
   836         buf [count++] = 0;      // Session.compression_null
   348         converted[pointer++] = 0;      // Session.compression_null
   837 
   349 
   838         /*
   350         /*
   839          * Fill in lengths of the messages we synthesized (nested:
   351          * Fill in lengths of the messages we synthesized (nested:
   840          * V3 handshake message within V3 record) and then return
   352          * V3 handshake message within V3 record).
   841          */
   353          */
   842         buf [3] = (byte) (count - headerSize);
   354         // Note: need not to set the header actually.
   843         buf [4] = (byte) ((count - headerSize) >>> 8);
   355         int fragLen = pointer - 5;                      // TLSPlaintext.length
   844 
   356         converted[3] = (byte)((fragLen >>> 8) & 0xFF);
   845         buf [headerSize + 1] = 0;
   357         converted[4] = (byte)(fragLen & 0xFF);
   846         buf [headerSize + 2] = (byte) (((count - headerSize) - 4) >>> 8);
   358 
   847         buf [headerSize + 3] = (byte) ((count - headerSize) - 4);
   359         /*
   848 
   360          * Handshake.length, length of ClientHello message
   849         pos = headerSize;
   361          */
   850     }
   362         fragLen = pointer - 9;                          // Handshake.length
   851 
   363         converted[6] = (byte)((fragLen >>> 16) & 0xFF);
   852     /**
   364         converted[7] = (byte)((fragLen >>> 8) & 0xFF);
   853      * Return a description for the given content type. This method should be
   365         converted[8] = (byte)(fragLen & 0xFF);
   854      * in Record, but since that is an interface this is not possible.
   366 
   855      * Called from InputRecord and OutputRecord.
   367         // consume the full record
   856      */
   368         packet.position(srcPos + recordLen);
   857     static String contentName(int contentType) {
   369 
   858         switch (contentType) {
   370         // Need no header bytes.
   859         case ct_change_cipher_spec:
   371         return ByteBuffer.wrap(converted, 5, pointer - 5);  // 5: header size
   860             return "Change Cipher Spec";
   372     }
   861         case ct_alert:
   373 
   862             return "Alert";
   374     static ByteBuffer decrypt(Authenticator authenticator, CipherBox box,
   863         case ct_handshake:
   375             byte contentType, ByteBuffer bb) throws BadPaddingException {
   864             return "Handshake";
   376 
   865         case ct_application_data:
   377         return decrypt(authenticator, box, contentType, bb, null);
   866             return "Application Data";
   378     }
   867         default:
   379 
   868             return "contentType = " + contentType;
   380     static ByteBuffer decrypt(Authenticator authenticator,
   869         }
   381             CipherBox box, byte contentType, ByteBuffer bb,
   870     }
   382             byte[] sequence) throws BadPaddingException {
   871 
   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(
       
   561             byte[] buffer, int offset, byte[] tag) {
       
   562 
       
   563         // An array of hits is used to prevent Hotspot optimization for
       
   564         // the purpose of a constant-time check.
       
   565         int[] results = {0, 0};    // {missed #, matched #}
       
   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     }
   872 }
   606 }
       
   607