jdk/src/share/classes/sun/security/ssl/InputRecord.java
changeset 16126 aad71cf676d7
parent 16067 36055e4b5305
parent 16113 946ec9b22004
child 16913 a6f4d1626ad9
equal deleted inserted replaced
16069:469ad49d6185 16126:aad71cf676d7
     1 /*
     1 /*
     2  * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
   131 
   131 
   132     HandshakeHash getHandshakeHash() {
   132     HandshakeHash getHandshakeHash() {
   133         return handshakeHash;
   133         return handshakeHash;
   134     }
   134     }
   135 
   135 
   136     /*
   136     void decrypt(MAC signer, CipherBox box) throws BadPaddingException {
   137      * Verify and remove the MAC ... used for all records.
   137 
   138      */
   138         BadPaddingException reservedBPE = null;
   139     boolean checkMAC(MAC signer) {
   139         int tagLen = signer.MAClen();
   140         int len = signer.MAClen();
   140         int cipheredLength = count - headerSize;
   141         if (len == 0) { // no mac
   141 
   142             return true;
   142         if (!box.isNullCipher()) {
   143         }
   143             // sanity check length of the ciphertext
   144 
   144             if (!box.sanityCheck(tagLen, cipheredLength)) {
   145         int offset = count - len;
   145                 throw new BadPaddingException(
   146 
   146                     "ciphertext sanity check failed");
   147         if (offset < headerSize) {
   147             }
   148             // data length would be negative, something is wrong
   148 
   149             return false;
   149             try {
   150         }
   150                 // Note that the CipherBox.decrypt() does not change
   151 
   151                 // the capacity of the buffer.
   152         byte[] mac = signer.compute(contentType(), buf,
   152                 count = headerSize +
   153             headerSize, offset - headerSize);
   153                         box.decrypt(buf, headerSize, cipheredLength, tagLen);
   154 
   154             } catch (BadPaddingException bpe) {
   155         if (len != mac.length) {
   155                 // RFC 2246 states that decryption_failed should be used
       
   156                 // for this purpose. However, that allows certain attacks,
       
   157                 // so we just send bad record MAC. We also need to make
       
   158                 // sure to always check the MAC to avoid a timing attack
       
   159                 // for the same issue. See paper by Vaudenay et al and the
       
   160                 // update in RFC 4346/5246.
       
   161                 //
       
   162                 // Failover to message authentication code checking.
       
   163                 reservedBPE = bpe;
       
   164             }
       
   165         }
       
   166 
       
   167         if (tagLen != 0) {
       
   168             int macOffset = count - tagLen;
       
   169             int contentLen = macOffset - headerSize;
       
   170 
       
   171             // Note that although it is not necessary, we run the same MAC
       
   172             // computation and comparison on the payload for both stream
       
   173             // cipher and CBC block cipher.
       
   174             if (contentLen < 0) {
       
   175                 // negative data length, something is wrong
       
   176                 if (reservedBPE == null) {
       
   177                     reservedBPE = new BadPaddingException("bad record");
       
   178                 }
       
   179 
       
   180                 // set offset of the dummy MAC
       
   181                 macOffset = headerSize + cipheredLength - tagLen;
       
   182                 contentLen = macOffset - headerSize;
       
   183             }
       
   184 
       
   185             count -= tagLen;  // Set the count before any MAC checking
       
   186                               // exception occurs, so that the following
       
   187                               // process can read the actual decrypted
       
   188                               // content (minus the MAC) in the fragment
       
   189                               // if necessary.
       
   190 
       
   191             // Run MAC computation and comparison on the payload.
       
   192             if (checkMacTags(contentType(),
       
   193                     buf, headerSize, contentLen, signer, false)) {
       
   194                 if (reservedBPE == null) {
       
   195                     reservedBPE = new BadPaddingException("bad record MAC");
       
   196                 }
       
   197             }
       
   198 
       
   199             // Run MAC computation and comparison on the remainder.
       
   200             //
       
   201             // It is only necessary for CBC block cipher.  It is used to get a
       
   202             // constant time of MAC computation and comparison on each record.
       
   203             if (box.isCBCMode()) {
       
   204                 int remainingLen = calculateRemainingLen(
       
   205                                         signer, cipheredLength, contentLen);
       
   206 
       
   207                 // NOTE: remainingLen may be bigger (less than 1 block of the
       
   208                 // hash algorithm of the MAC) than the cipheredLength. However,
       
   209                 // We won't need to worry about it because we always use a
       
   210                 // maximum buffer for every record.  We need a change here if
       
   211                 // we use small buffer size in the future.
       
   212                 if (remainingLen > buf.length) {
       
   213                     // unlikely to happen, just a placehold
       
   214                     throw new RuntimeException(
       
   215                         "Internal buffer capacity error");
       
   216                 }
       
   217 
       
   218                 // Won't need to worry about the result on the remainder. And
       
   219                 // then we won't need to worry about what's actual data to
       
   220                 // check MAC tag on.  We start the check from the header of the
       
   221                 // buffer so that we don't need to construct a new byte buffer.
       
   222                 checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
       
   223             }
       
   224         }
       
   225 
       
   226         // Is it a failover?
       
   227         if (reservedBPE != null) {
       
   228             throw reservedBPE;
       
   229         }
       
   230     }
       
   231 
       
   232     /*
       
   233      * Run MAC computation and comparison
       
   234      *
       
   235      * Please DON'T change the content of the byte buffer parameter!
       
   236      */
       
   237     static boolean checkMacTags(byte contentType, byte[] buffer,
       
   238             int offset, int contentLen, MAC signer, boolean isSimulated) {
       
   239 
       
   240         int tagLen = signer.MAClen();
       
   241         byte[] hash = signer.compute(
       
   242                 contentType, buffer, offset, contentLen, isSimulated);
       
   243         if (hash == null || tagLen != hash.length) {
       
   244             // Something is wrong with MAC implementation.
   156             throw new RuntimeException("Internal MAC error");
   245             throw new RuntimeException("Internal MAC error");
   157         }
   246         }
   158 
   247 
   159         for (int i = 0; i < len; i++) {
   248         int[] results = compareMacTags(buffer, offset + contentLen, hash);
   160             if (buf[offset + i] != mac[i]) {
   249         return (results[0] != 0);
   161                 return false;
   250     }
   162             }
   251 
   163         }
   252     /*
   164         count -= len;
   253      * A constant-time comparison of the MAC tags.
   165         return true;
   254      *
   166     }
   255      * Please DON'T change the content of the byte buffer parameter!
   167 
   256      */
   168     void decrypt(CipherBox box) throws BadPaddingException {
   257     private static int[] compareMacTags(
   169         int len = count - headerSize;
   258             byte[] buffer, int offset, byte[] tag) {
   170         count = headerSize + box.decrypt(buf, headerSize, len);
   259 
   171     }
   260         // An array of hits is used to prevent Hotspot optimization for
   172 
   261         // the purpose of a constant-time check.
       
   262         int[] results = {0, 0};    // {missed #, matched #}
       
   263 
       
   264         // The caller ensures there are enough bytes available in the buffer.
       
   265         // So we won't need to check the length of the buffer.
       
   266         for (int i = 0; i < tag.length; i++) {
       
   267             if (buffer[offset + i] != tag[i]) {
       
   268                 results[0]++;       // mismatched bytes
       
   269             } else {
       
   270                 results[1]++;       // matched bytes
       
   271             }
       
   272         }
       
   273 
       
   274         return results;
       
   275     }
       
   276 
       
   277     /*
       
   278      * Calculate the length of a dummy buffer to run MAC computation
       
   279      * and comparison on the remainder.
       
   280      *
       
   281      * The caller MUST ensure that the fullLen is not less than usedLen.
       
   282      */
       
   283     static int calculateRemainingLen(
       
   284             MAC signer, int fullLen, int usedLen) {
       
   285 
       
   286         int blockLen = signer.hashBlockLen();
       
   287         int minimalPaddingLen = signer.minimalPaddingLen();
       
   288 
       
   289         // (blockLen - minimalPaddingLen) is the maximum message size of
       
   290         // the last block of hash function operation. See FIPS 180-4, or
       
   291         // MD5 specification.
       
   292         fullLen += 13 - (blockLen - minimalPaddingLen);
       
   293         usedLen += 13 - (blockLen - minimalPaddingLen);
       
   294 
       
   295         // Note: fullLen is always not less than usedLen, and blockLen
       
   296         // is always bigger than minimalPaddingLen, so we don't worry
       
   297         // about negative values. 0x01 is added to the result to ensure
       
   298         // that the return value is positive.  The extra one byte does
       
   299         // not impact the overall MAC compression function evaluations.
       
   300         return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
       
   301                 Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen();
       
   302     }
   173 
   303 
   174     /*
   304     /*
   175      * Well ... hello_request messages are _never_ hashed since we can't
   305      * Well ... hello_request messages are _never_ hashed since we can't
   176      * know when they'd appear in the sequence.
   306      * know when they'd appear in the sequence.
   177      */
   307      */