1 /*
   2  * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package sun.security.ssl;
  28 
  29 import java.io.ByteArrayOutputStream;
  30 import java.security.*;
  31 import java.util.Locale;
  32 import java.nio.ByteBuffer;
  33 
  34 /**
  35  * Abstraction for the SSL/TLS hash of all handshake messages that is
  36  * maintained to verify the integrity of the negotiation. Internally,
  37  * it consists of an MD5 and an SHA1 digest. They are used in the client
  38  * and server finished messages and in certificate verify messages (if sent).
  39  *
  40  * This class transparently deals with cloneable and non-cloneable digests.
  41  *
  42  * This class now supports TLS 1.2 also. The key difference for TLS 1.2
  43  * is that you cannot determine the hash algorithms for CertificateVerify
  44  * at a early stage. On the other hand, it's simpler than TLS 1.1 (and earlier)
  45  * that there is no messy MD5+SHA1 digests.
  46  *
  47  * You need to obey these conventions when using this class:
  48  *
  49  * 1. protocolDetermined(version) should be called when the negotiated
  50  * protocol version is determined.
  51  *
  52  * 2. Before protocolDetermined() is called, only update(), and reset()
  53  * and setFinishedAlg() can be called.
  54  *
  55  * 3. After protocolDetermined() is called, reset() cannot be called.
  56  *
  57  * 4. After protocolDetermined() is called, if the version is pre-TLS 1.2,
  58  * getFinishedHash() cannot be called. Otherwise,
  59  * getMD5Clone() and getSHAClone() cannot be called.
  60  *
  61  * 5. getMD5Clone() and getSHAClone() can only be called after
  62  * protocolDetermined() is called and version is pre-TLS 1.2.
  63  *
  64  * 6. getFinishedHash() can only be called after protocolDetermined()
  65  * and setFinishedAlg() have been called and the version is TLS 1.2.
  66  *
  67  * Suggestion: Call protocolDetermined() and setFinishedAlg()
  68  * as early as possible.
  69  *
  70  * Example:
  71  * <pre>
  72  * HandshakeHash hh = new HandshakeHash(...)
  73  * hh.protocolDetermined(ProtocolVersion.TLS12);
  74  * hh.update(clientHelloBytes);
  75  * hh.setFinishedAlg("SHA-256");
  76  * hh.update(serverHelloBytes);
  77  * ...
  78  * hh.update(CertificateVerifyBytes);
  79  * ...
  80  * hh.update(finished1);
  81  * byte[] finDigest1 = hh.getFinishedHash();
  82  * hh.update(finished2);
  83  * byte[] finDigest2 = hh.getFinishedHash();
  84  * </pre>
  85  */
  86 final class HandshakeHash {
  87 
  88     // Common
  89 
  90     // -1:  unknown
  91     //  1:  <=TLS 1.1
  92     //  2:  TLS 1.2
  93     private int version = -1;
  94     private ByteArrayOutputStream data = new ByteArrayOutputStream();
  95 
  96     // For TLS 1.1
  97     private MessageDigest md5, sha;
  98     private final int clonesNeeded;    // needs to be saved for later use
  99 
 100     // For TLS 1.2
 101     private MessageDigest finMD;
 102 
 103     // Cache for input record handshake hash computation
 104     private ByteArrayOutputStream reserve = new ByteArrayOutputStream();
 105 
 106     /**
 107      * Create a new HandshakeHash. needCertificateVerify indicates whether
 108      * a hash for the certificate verify message is required.
 109      */
 110     HandshakeHash(boolean needCertificateVerify) {
 111         // We may rework the code later, but for now we use hard-coded number
 112         // of clones if the underlying MessageDigests are not cloneable.
 113         //
 114         // The number used here is based on the current handshake protocols and
 115         // implementation.  It may be changed if the handshake processe gets
 116         // changed in the future, for example adding a new extension that
 117         // requires handshake hash.  Please be careful about the number of
 118         // clones if additional handshak hash is required in the future.
 119         //
 120         // For the current implementation, the handshake hash is required for
 121         // the following items:
 122         //     . CertificateVerify handshake message (optional)
 123         //     . client Finished handshake message
 124         //     . server Finished Handshake message
 125         //     . the extended Master Secret extension [RFC 7627]
 126         //
 127         // Note that a late call to server setNeedClientAuth dose not update
 128         // the number of clones.  We may address the issue later.
 129         //
 130         // Note for safety, we allocate one more clone for the current
 131         // implementation.  We may consider it more carefully in the future
 132         // for the exact number or rework the code in a different way.
 133         clonesNeeded = needCertificateVerify ? 5 : 4;
 134     }
 135 
 136     void reserve(ByteBuffer input) {
 137         if (input.hasArray()) {
 138             reserve.write(input.array(),
 139                     input.position() + input.arrayOffset(), input.remaining());
 140         } else {
 141             int inPos = input.position();
 142             byte[] holder = new byte[input.remaining()];
 143             input.get(holder);
 144             input.position(inPos);
 145             reserve.write(holder, 0, holder.length);
 146         }
 147     }
 148 
 149     void reserve(byte[] b, int offset, int len) {
 150         reserve.write(b, offset, len);
 151     }
 152 
 153     void reload() {
 154         if (reserve.size() != 0) {
 155             byte[] bytes = reserve.toByteArray();
 156             reserve.reset();
 157             update(bytes, 0, bytes.length);
 158         }
 159     }
 160 
 161     void update(ByteBuffer input) {
 162 
 163         // reload if there are reserved messages.
 164         reload();
 165 
 166         int inPos = input.position();
 167         switch (version) {
 168             case 1:
 169                 md5.update(input);
 170                 input.position(inPos);
 171 
 172                 sha.update(input);
 173                 input.position(inPos);
 174 
 175                 break;
 176             default:
 177                 if (finMD != null) {
 178                     finMD.update(input);
 179                     input.position(inPos);
 180                 }
 181                 if (input.hasArray()) {
 182                     data.write(input.array(),
 183                             inPos + input.arrayOffset(), input.remaining());
 184                 } else {
 185                     byte[] holder = new byte[input.remaining()];
 186                     input.get(holder);
 187                     input.position(inPos);
 188                     data.write(holder, 0, holder.length);
 189                 }
 190                 break;
 191         }
 192     }
 193 
 194     void update(byte handshakeType, byte[] handshakeBody) {
 195 
 196         // reload if there are reserved messages.
 197         reload();
 198 
 199         switch (version) {
 200             case 1:
 201                 md5.update(handshakeType);
 202                 sha.update(handshakeType);
 203 
 204                 md5.update((byte)((handshakeBody.length >> 16) & 0xFF));
 205                 sha.update((byte)((handshakeBody.length >> 16) & 0xFF));
 206                 md5.update((byte)((handshakeBody.length >> 8) & 0xFF));
 207                 sha.update((byte)((handshakeBody.length >> 8) & 0xFF));
 208                 md5.update((byte)(handshakeBody.length & 0xFF));
 209                 sha.update((byte)(handshakeBody.length & 0xFF));
 210 
 211                 md5.update(handshakeBody);
 212                 sha.update(handshakeBody);
 213                 break;
 214             default:
 215                 if (finMD != null) {
 216                     finMD.update(handshakeType);
 217                     finMD.update((byte)((handshakeBody.length >> 16) & 0xFF));
 218                     finMD.update((byte)((handshakeBody.length >> 8) & 0xFF));
 219                     finMD.update((byte)(handshakeBody.length & 0xFF));
 220                     finMD.update(handshakeBody);
 221                 }
 222                 data.write(handshakeType);
 223                 data.write((byte)((handshakeBody.length >> 16) & 0xFF));
 224                 data.write((byte)((handshakeBody.length >> 8) & 0xFF));
 225                 data.write((byte)(handshakeBody.length & 0xFF));
 226                 data.write(handshakeBody, 0, handshakeBody.length);
 227                 break;
 228         }
 229     }
 230 
 231     void update(byte[] b, int offset, int len) {
 232 
 233         // reload if there are reserved messages.
 234         reload();
 235 
 236         switch (version) {
 237             case 1:
 238                 md5.update(b, offset, len);
 239                 sha.update(b, offset, len);
 240                 break;
 241             default:
 242                 if (finMD != null) {
 243                     finMD.update(b, offset, len);
 244                 }
 245                 data.write(b, offset, len);
 246                 break;
 247         }
 248     }
 249 
 250     /**
 251      * Reset the remaining digests. Note this does *not* reset the number of
 252      * digest clones that can be obtained. Digests that have already been
 253      * cloned and are gone remain gone.
 254      */
 255     void reset() {
 256         if (version != -1) {
 257             throw new RuntimeException(
 258                     "reset() can be only be called before protocolDetermined");
 259         }
 260         data.reset();
 261     }
 262 
 263 
 264     void protocolDetermined(ProtocolVersion pv) {
 265 
 266         // Do not set again, will ignore
 267         if (version != -1) {
 268             return;
 269         }
 270 
 271         if (pv.maybeDTLSProtocol()) {
 272             version = pv.compareTo(ProtocolVersion.DTLS12) >= 0 ? 2 : 1;
 273         } else {
 274             version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
 275         }
 276         switch (version) {
 277             case 1:
 278                 // initiate md5, sha and call update on saved array
 279                 try {
 280                     md5 = CloneableDigest.getDigest("MD5", clonesNeeded);
 281                     sha = CloneableDigest.getDigest("SHA", clonesNeeded);
 282                 } catch (NoSuchAlgorithmException e) {
 283                     throw new RuntimeException
 284                                 ("Algorithm MD5 or SHA not available", e);
 285                 }
 286                 byte[] bytes = data.toByteArray();
 287                 update(bytes, 0, bytes.length);
 288                 break;
 289             case 2:
 290                 break;
 291         }
 292     }
 293 
 294     /////////////////////////////////////////////////////////////
 295     // Below are old methods for pre-TLS 1.1
 296     /////////////////////////////////////////////////////////////
 297 
 298     /**
 299      * Return a new MD5 digest updated with all data hashed so far.
 300      */
 301     MessageDigest getMD5Clone() {
 302         if (version != 1) {
 303             throw new RuntimeException(
 304                     "getMD5Clone() can be only be called for TLS 1.1");
 305         }
 306         return cloneDigest(md5);
 307     }
 308 
 309     /**
 310      * Return a new SHA digest updated with all data hashed so far.
 311      */
 312     MessageDigest getSHAClone() {
 313         if (version != 1) {
 314             throw new RuntimeException(
 315                     "getSHAClone() can be only be called for TLS 1.1");
 316         }
 317         return cloneDigest(sha);
 318     }
 319 
 320     private static MessageDigest cloneDigest(MessageDigest digest) {
 321         try {
 322             return (MessageDigest)digest.clone();
 323         } catch (CloneNotSupportedException e) {
 324             // cannot occur for digests generated via CloneableDigest
 325             throw new RuntimeException("Could not clone digest", e);
 326         }
 327     }
 328 
 329     /////////////////////////////////////////////////////////////
 330     // Below are new methods for TLS 1.2
 331     /////////////////////////////////////////////////////////////
 332 
 333     private static String normalizeAlgName(String alg) {
 334         alg = alg.toUpperCase(Locale.US);
 335         if (alg.startsWith("SHA")) {
 336             if (alg.length() == 3) {
 337                 return "SHA-1";
 338             }
 339             if (alg.charAt(3) != '-') {
 340                 return "SHA-" + alg.substring(3);
 341             }
 342         }
 343         return alg;
 344     }
 345     /**
 346      * Specifies the hash algorithm used in Finished. This should be called
 347      * based in info in ServerHello.
 348      * Can be called multiple times.
 349      */
 350     void setFinishedAlg(String s) {
 351         if (s == null) {
 352             throw new RuntimeException(
 353                     "setFinishedAlg's argument cannot be null");
 354         }
 355 
 356         // Can be called multiple times, but only set once
 357         if (finMD != null) return;
 358 
 359         try {
 360             // See comment in the contructor.
 361             finMD = CloneableDigest.getDigest(normalizeAlgName(s), 4);
 362         } catch (NoSuchAlgorithmException e) {
 363             throw new Error(e);
 364         }
 365         finMD.update(data.toByteArray());
 366     }
 367 
 368     byte[] getAllHandshakeMessages() {
 369         return data.toByteArray();
 370     }
 371 
 372     /**
 373      * Calculates the hash in Finished. Must be called after setFinishedAlg().
 374      * This method can be called twice, for Finished messages of the server
 375      * side and client side respectively.
 376      */
 377     byte[] getFinishedHash() {
 378         try {
 379             return cloneDigest(finMD).digest();
 380         } catch (Exception e) {
 381             throw new Error("Error during hash calculation", e);
 382         }
 383     }
 384 }
 385 
 386 /**
 387  * A wrapper for MessageDigests that simulates cloning of non-cloneable
 388  * digests. It uses the standard MessageDigest API and therefore can be used
 389  * transparently in place of a regular digest.
 390  *
 391  * Note that we extend the MessageDigest class directly rather than
 392  * MessageDigestSpi. This works because MessageDigest was originally designed
 393  * this way in the JDK 1.1 days which allows us to avoid creating an internal
 394  * provider.
 395  *
 396  * It can be "cloned" a limited number of times, which is specified at
 397  * construction time. This is achieved by internally maintaining n digests
 398  * in parallel. Consequently, it is only 1/n-th times as fast as the original
 399  * digest.
 400  *
 401  * Example:
 402  *   MessageDigest md = CloneableDigest.getDigest("SHA", 2);
 403  *   md.update(data1);
 404  *   MessageDigest md2 = (MessageDigest)md.clone();
 405  *   md2.update(data2);
 406  *   byte[] d1 = md2.digest(); // digest of data1 || data2
 407  *   md.update(data3);
 408  *   byte[] d2 = md.digest();  // digest of data1 || data3
 409  *
 410  * This class is not thread safe.
 411  *
 412  */
 413 final class CloneableDigest extends MessageDigest implements Cloneable {
 414 
 415     /**
 416      * The individual MessageDigests. Initially, all elements are non-null.
 417      * When clone() is called, the non-null element with the maximum index is
 418      * returned and the array element set to null.
 419      *
 420      * All non-null element are always in the same state.
 421      */
 422     private final MessageDigest[] digests;
 423 
 424     private CloneableDigest(MessageDigest digest, int n, String algorithm)
 425             throws NoSuchAlgorithmException {
 426         super(algorithm);
 427         digests = new MessageDigest[n];
 428         digests[0] = digest;
 429         for (int i = 1; i < n; i++) {
 430             digests[i] = JsseJce.getMessageDigest(algorithm);
 431         }
 432     }
 433 
 434     /**
 435      * Return a MessageDigest for the given algorithm that can be cloned the
 436      * specified number of times. If the default implementation supports
 437      * cloning, it is returned. Otherwise, an instance of this class is
 438      * returned.
 439      */
 440     static MessageDigest getDigest(String algorithm, int n)
 441             throws NoSuchAlgorithmException {
 442         MessageDigest digest = JsseJce.getMessageDigest(algorithm);
 443         try {
 444             digest.clone();
 445             // already cloneable, use it
 446             return digest;
 447         } catch (CloneNotSupportedException e) {
 448             return new CloneableDigest(digest, n, algorithm);
 449         }
 450     }
 451 
 452     /**
 453      * Check if this object is still usable. If it has already been cloned the
 454      * maximum number of times, there are no digests left and this object can no
 455      * longer be used.
 456      */
 457     private void checkState() {
 458         // XXX handshaking currently doesn't stop updating hashes...
 459         // if (digests[0] == null) {
 460         //     throw new IllegalStateException("no digests left");
 461         // }
 462     }
 463 
 464     @Override
 465     protected int engineGetDigestLength() {
 466         checkState();
 467         return digests[0].getDigestLength();
 468     }
 469 
 470     @Override
 471     protected void engineUpdate(byte b) {
 472         checkState();
 473         for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
 474             digests[i].update(b);
 475         }
 476     }
 477 
 478     @Override
 479     protected void engineUpdate(byte[] b, int offset, int len) {
 480         checkState();
 481         for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
 482             digests[i].update(b, offset, len);
 483         }
 484     }
 485 
 486     @Override
 487     protected byte[] engineDigest() {
 488         checkState();
 489         byte[] digest = digests[0].digest();
 490         digestReset();
 491         return digest;
 492     }
 493 
 494     @Override
 495     protected int engineDigest(byte[] buf, int offset, int len)
 496             throws DigestException {
 497         checkState();
 498         int n = digests[0].digest(buf, offset, len);
 499         digestReset();
 500         return n;
 501     }
 502 
 503     /**
 504      * Reset all digests after a digest() call. digests[0] has already been
 505      * implicitly reset by the digest() call and does not need to be reset
 506      * again.
 507      */
 508     private void digestReset() {
 509         for (int i = 1; (i < digests.length) && (digests[i] != null); i++) {
 510             digests[i].reset();
 511         }
 512     }
 513 
 514     @Override
 515     protected void engineReset() {
 516         checkState();
 517         for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
 518             digests[i].reset();
 519         }
 520     }
 521 
 522     @Override
 523     public Object clone() {
 524         checkState();
 525         for (int i = digests.length - 1; i >= 0; i--) {
 526             if (digests[i] != null) {
 527                 MessageDigest digest = digests[i];
 528                 digests[i] = null;
 529                 return digest;
 530             }
 531         }
 532         // cannot occur
 533         throw new InternalError();
 534     }
 535 
 536 }