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