1 /*
   2  * Copyright (c) 2002, 2012, 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 
  33 /**
  34  * Abstraction for the SSL/TLS hash of all handshake messages that is
  35  * maintained to verify the integrity of the negotiation. Internally,
  36  * it consists of an MD5 and an SHA1 digest. They are used in the client
  37  * and server finished messages and in certificate verify messages (if sent).
  38  *
  39  * This class transparently deals with cloneable and non-cloneable digests.
  40  *
  41  * This class now supports TLS 1.2 also. The key difference for TLS 1.2
  42  * is that you cannot determine the hash algorithms for CertificateVerify
  43  * at a early stage. On the other hand, it's simpler than TLS 1.1 (and earlier)
  44  * that there is no messy MD5+SHA1 digests.
  45  *
  46  * You need to obey these conventions when using this class:
  47  *
  48  * 1. protocolDetermined(version) should be called when the negotiated
  49  * protocol version is determined.
  50  *
  51  * 2. Before protocolDetermined() is called, only update(), and reset()
  52  * and setFinishedAlg() can be called.
  53  *
  54  * 3. After protocolDetermined() is called, reset() cannot be called.
  55  *
  56  * 4. After protocolDetermined() is called, if the version is pre-TLS 1.2,
  57  * getFinishedHash() cannot be called. Otherwise,
  58  * getMD5Clone() and getSHAClone() cannot be called.
  59  *
  60  * 5. getMD5Clone() and getSHAClone() can only be called after
  61  * protocolDetermined() is called and version is pre-TLS 1.2.
  62  *
  63  * 6. getFinishedHash() can only be called after protocolDetermined()
  64  * and setFinishedAlg() have been called and the version is TLS 1.2.
  65  *
  66  * Suggestion: Call protocolDetermined() and setFinishedAlg()
  67  * as early as possible.
  68  *
  69  * Example:
  70  * <pre>
  71  * HandshakeHash hh = new HandshakeHash(...)
  72  * hh.protocolDetermined(ProtocolVersion.TLS12);
  73  * hh.update(clientHelloBytes);
  74  * hh.setFinishedAlg("SHA-256");
  75  * hh.update(serverHelloBytes);
  76  * ...
  77  * hh.update(CertificateVerifyBytes);
  78  * ...
  79  * hh.update(finished1);
  80  * byte[] finDigest1 = hh.getFinishedHash();
  81  * hh.update(finished2);
  82  * byte[] finDigest2 = hh.getFinishedHash();
  83  * </pre>
  84  */
  85 final class HandshakeHash {
  86 
  87     // Common
  88 
  89     // -1:  unknown
  90     //  1:  <=TLS 1.1
  91     //  2:  TLS 1.2
  92     private int version = -1;
  93     private ByteArrayOutputStream data = new ByteArrayOutputStream();
  94 
  95     // For TLS 1.1
  96     private MessageDigest md5, sha;
  97     private final int clonesNeeded;    // needs to be saved for later use
  98 
  99     // For TLS 1.2
 100     private MessageDigest finMD;
 101 
 102     /**
 103      * Create a new HandshakeHash. needCertificateVerify indicates whether
 104      * a hash for the certificate verify message is required.
 105      */
 106     HandshakeHash(boolean needCertificateVerify) {
 107         clonesNeeded = needCertificateVerify ? 3 : 2;
 108     }
 109 
 110     void update(byte[] b, int offset, int len) {
 111         switch (version) {
 112             case 1:
 113                 md5.update(b, offset, len);
 114                 sha.update(b, offset, len);
 115                 break;
 116             default:
 117                 if (finMD != null) {
 118                     finMD.update(b, offset, len);
 119                 }
 120                 data.write(b, offset, len);
 121                 break;
 122         }
 123     }
 124 
 125     /**
 126      * Reset the remaining digests. Note this does *not* reset the number of
 127      * digest clones that can be obtained. Digests that have already been
 128      * cloned and are gone remain gone.
 129      */
 130     void reset() {
 131         if (version != -1) {
 132             throw new RuntimeException(
 133                     "reset() can be only be called before protocolDetermined");
 134         }
 135         data.reset();
 136     }
 137 
 138 
 139     void protocolDetermined(ProtocolVersion pv) {
 140 
 141         // Do not set again, will ignore
 142         if (version != -1) return;
 143 
 144         version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
 145         switch (version) {
 146             case 1:
 147                 // initiate md5, sha and call update on saved array
 148                 try {
 149                     md5 = CloneableDigest.getDigest("MD5", clonesNeeded);
 150                     sha = CloneableDigest.getDigest("SHA", clonesNeeded);
 151                 } catch (NoSuchAlgorithmException e) {
 152                     throw new RuntimeException
 153                                 ("Algorithm MD5 or SHA not available", e);
 154                 }
 155                 byte[] bytes = data.toByteArray();
 156                 update(bytes, 0, bytes.length);
 157                 break;
 158             case 2:
 159                 break;
 160         }
 161     }
 162 
 163     /////////////////////////////////////////////////////////////
 164     // Below are old methods for pre-TLS 1.1
 165     /////////////////////////////////////////////////////////////
 166 
 167     /**
 168      * Return a new MD5 digest updated with all data hashed so far.
 169      */
 170     MessageDigest getMD5Clone() {
 171         if (version != 1) {
 172             throw new RuntimeException(
 173                     "getMD5Clone() can be only be called for TLS 1.1");
 174         }
 175         return cloneDigest(md5);
 176     }
 177 
 178     /**
 179      * Return a new SHA digest updated with all data hashed so far.
 180      */
 181     MessageDigest getSHAClone() {
 182         if (version != 1) {
 183             throw new RuntimeException(
 184                     "getSHAClone() can be only be called for TLS 1.1");
 185         }
 186         return cloneDigest(sha);
 187     }
 188 
 189     private static MessageDigest cloneDigest(MessageDigest digest) {
 190         try {
 191             return (MessageDigest)digest.clone();
 192         } catch (CloneNotSupportedException e) {
 193             // cannot occur for digests generated via CloneableDigest
 194             throw new RuntimeException("Could not clone digest", e);
 195         }
 196     }
 197 
 198     /////////////////////////////////////////////////////////////
 199     // Below are new methods for TLS 1.2
 200     /////////////////////////////////////////////////////////////
 201 
 202     private static String normalizeAlgName(String alg) {
 203         alg = alg.toUpperCase(Locale.US);
 204         if (alg.startsWith("SHA")) {
 205             if (alg.length() == 3) {
 206                 return "SHA-1";
 207             }
 208             if (alg.charAt(3) != '-') {
 209                 return "SHA-" + alg.substring(3);
 210             }
 211         }
 212         return alg;
 213     }
 214     /**
 215      * Specifies the hash algorithm used in Finished. This should be called
 216      * based in info in ServerHello.
 217      * Can be called multiple times.
 218      */
 219     void setFinishedAlg(String s) {
 220         if (s == null) {
 221             throw new RuntimeException(
 222                     "setFinishedAlg's argument cannot be null");
 223         }
 224 
 225         // Can be called multiple times, but only set once
 226         if (finMD != null) return;
 227 
 228         try {
 229             finMD = CloneableDigest.getDigest(normalizeAlgName(s), 2);
 230         } catch (NoSuchAlgorithmException e) {
 231             throw new Error(e);
 232         }
 233         finMD.update(data.toByteArray());
 234     }
 235 
 236     byte[] getAllHandshakeMessages() {
 237         return data.toByteArray();
 238     }
 239 
 240     /**
 241      * Calculates the hash in Finished. Must be called after setFinishedAlg().
 242      * This method can be called twice, for Finished messages of the server
 243      * side and client side respectively.
 244      */
 245     byte[] getFinishedHash() {
 246         try {
 247             return cloneDigest(finMD).digest();
 248         } catch (Exception e) {
 249             throw new Error("BAD");
 250         }
 251     }
 252 }
 253 
 254 /**
 255  * A wrapper for MessageDigests that simulates cloning of non-cloneable
 256  * digests. It uses the standard MessageDigest API and therefore can be used
 257  * transparently in place of a regular digest.
 258  *
 259  * Note that we extend the MessageDigest class directly rather than
 260  * MessageDigestSpi. This works because MessageDigest was originally designed
 261  * this way in the JDK 1.1 days which allows us to avoid creating an internal
 262  * provider.
 263  *
 264  * It can be "cloned" a limited number of times, which is specified at
 265  * construction time. This is achieved by internally maintaining n digests
 266  * in parallel. Consequently, it is only 1/n-th times as fast as the original
 267  * digest.
 268  *
 269  * Example:
 270  *   MessageDigest md = CloneableDigest.getDigest("SHA", 2);
 271  *   md.update(data1);
 272  *   MessageDigest md2 = (MessageDigest)md.clone();
 273  *   md2.update(data2);
 274  *   byte[] d1 = md2.digest(); // digest of data1 || data2
 275  *   md.update(data3);
 276  *   byte[] d2 = md.digest();  // digest of data1 || data3
 277  *
 278  * This class is not thread safe.
 279  *
 280  */
 281 final class CloneableDigest extends MessageDigest implements Cloneable {
 282 
 283     /**
 284      * The individual MessageDigests. Initially, all elements are non-null.
 285      * When clone() is called, the non-null element with the maximum index is
 286      * returned and the array element set to null.
 287      *
 288      * All non-null element are always in the same state.
 289      */
 290     private final MessageDigest[] digests;
 291 
 292     private CloneableDigest(MessageDigest digest, int n, String algorithm)
 293             throws NoSuchAlgorithmException {
 294         super(algorithm);
 295         digests = new MessageDigest[n];
 296         digests[0] = digest;
 297         for (int i = 1; i < n; i++) {
 298             digests[i] = JsseJce.getMessageDigest(algorithm);
 299         }
 300     }
 301 
 302     /**
 303      * Return a MessageDigest for the given algorithm that can be cloned the
 304      * specified number of times. If the default implementation supports
 305      * cloning, it is returned. Otherwise, an instance of this class is
 306      * returned.
 307      */
 308     static MessageDigest getDigest(String algorithm, int n)
 309             throws NoSuchAlgorithmException {
 310         MessageDigest digest = JsseJce.getMessageDigest(algorithm);
 311         try {
 312             digest.clone();
 313             // already cloneable, use it
 314             return digest;
 315         } catch (CloneNotSupportedException e) {
 316             return new CloneableDigest(digest, n, algorithm);
 317         }
 318     }
 319 
 320     /**
 321      * Check if this object is still usable. If it has already been cloned the
 322      * maximum number of times, there are no digests left and this object can no
 323      * longer be used.
 324      */
 325     private void checkState() {
 326         // XXX handshaking currently doesn't stop updating hashes...
 327         // if (digests[0] == null) {
 328         //     throw new IllegalStateException("no digests left");
 329         // }
 330     }
 331 
 332     @Override
 333     protected int engineGetDigestLength() {
 334         checkState();
 335         return digests[0].getDigestLength();
 336     }
 337 
 338     @Override
 339     protected void engineUpdate(byte b) {
 340         checkState();
 341         for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
 342             digests[i].update(b);
 343         }
 344     }
 345 
 346     @Override
 347     protected void engineUpdate(byte[] b, int offset, int len) {
 348         checkState();
 349         for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
 350             digests[i].update(b, offset, len);
 351         }
 352     }
 353 
 354     @Override
 355     protected byte[] engineDigest() {
 356         checkState();
 357         byte[] digest = digests[0].digest();
 358         digestReset();
 359         return digest;
 360     }
 361 
 362     @Override
 363     protected int engineDigest(byte[] buf, int offset, int len)
 364             throws DigestException {
 365         checkState();
 366         int n = digests[0].digest(buf, offset, len);
 367         digestReset();
 368         return n;
 369     }
 370 
 371     /**
 372      * Reset all digests after a digest() call. digests[0] has already been
 373      * implicitly reset by the digest() call and does not need to be reset
 374      * again.
 375      */
 376     private void digestReset() {
 377         for (int i = 1; (i < digests.length) && (digests[i] != null); i++) {
 378             digests[i].reset();
 379         }
 380     }
 381 
 382     @Override
 383     protected void engineReset() {
 384         checkState();
 385         for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
 386             digests[i].reset();
 387         }
 388     }
 389 
 390     @Override
 391     public Object clone() {
 392         checkState();
 393         for (int i = digests.length - 1; i >= 0; i--) {
 394             if (digests[i] != null) {
 395                 MessageDigest digest = digests[i];
 396                 digests[i] = null;
 397                 return digest;
 398             }
 399         }
 400         // cannot occur
 401         throw new InternalError();
 402     }
 403 
 404 }