1/* 2 * Copyright (c) 2002, 2016, 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 27package sun.security.ssl; 28 29import java.io.ByteArrayOutputStream; 30import java.security.*; 31import java.util.Locale; 32import 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 */ 86final 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 clonesNeeded = needCertificateVerify ? 4 : 3; 112 } 113 114 void reserve(ByteBuffer input) { 115 if (input.hasArray()) { 116 reserve.write(input.array(), 117 input.position() + input.arrayOffset(), input.remaining()); 118 } else { 119 int inPos = input.position(); 120 byte[] holder = new byte[input.remaining()]; 121 input.get(holder); 122 input.position(inPos); 123 reserve.write(holder, 0, holder.length); 124 } 125 } 126 127 void reserve(byte[] b, int offset, int len) { 128 reserve.write(b, offset, len); 129 } 130 131 void reload() { 132 if (reserve.size() != 0) { 133 byte[] bytes = reserve.toByteArray(); 134 reserve.reset(); 135 update(bytes, 0, bytes.length); 136 } 137 } 138 139 void update(ByteBuffer input) { 140 141 // reload if there are reserved messages. 142 reload(); 143 144 int inPos = input.position(); 145 switch (version) { 146 case 1: 147 md5.update(input); 148 input.position(inPos); 149 150 sha.update(input); 151 input.position(inPos); 152 153 break; 154 default: 155 if (finMD != null) { 156 finMD.update(input); 157 input.position(inPos); 158 } 159 if (input.hasArray()) { 160 data.write(input.array(), 161 inPos + input.arrayOffset(), input.remaining()); 162 } else { 163 byte[] holder = new byte[input.remaining()]; 164 input.get(holder); 165 input.position(inPos); 166 data.write(holder, 0, holder.length); 167 } 168 break; 169 } 170 } 171 172 void update(byte handshakeType, byte[] handshakeBody) { 173 174 // reload if there are reserved messages. 175 reload(); 176 177 switch (version) { 178 case 1: 179 md5.update(handshakeType); 180 sha.update(handshakeType); 181 182 md5.update((byte)((handshakeBody.length >> 16) & 0xFF)); 183 sha.update((byte)((handshakeBody.length >> 16) & 0xFF)); 184 md5.update((byte)((handshakeBody.length >> 8) & 0xFF)); 185 sha.update((byte)((handshakeBody.length >> 8) & 0xFF)); 186 md5.update((byte)(handshakeBody.length & 0xFF)); 187 sha.update((byte)(handshakeBody.length & 0xFF)); 188 189 md5.update(handshakeBody); 190 sha.update(handshakeBody); 191 break; 192 default: 193 if (finMD != null) { 194 finMD.update(handshakeType); 195 finMD.update((byte)((handshakeBody.length >> 16) & 0xFF)); 196 finMD.update((byte)((handshakeBody.length >> 8) & 0xFF)); 197 finMD.update((byte)(handshakeBody.length & 0xFF)); 198 finMD.update(handshakeBody); 199 } 200 data.write(handshakeType); 201 data.write((byte)((handshakeBody.length >> 16) & 0xFF)); 202 data.write((byte)((handshakeBody.length >> 8) & 0xFF)); 203 data.write((byte)(handshakeBody.length & 0xFF)); 204 data.write(handshakeBody, 0, handshakeBody.length); 205 break; 206 } 207 } 208 209 void update(byte[] b, int offset, int len) { 210 211 // reload if there are reserved messages. 212 reload(); 213 214 switch (version) { 215 case 1: 216 md5.update(b, offset, len); 217 sha.update(b, offset, len); 218 break; 219 default: 220 if (finMD != null) { 221 finMD.update(b, offset, len); 222 } 223 data.write(b, offset, len); 224 break; 225 } 226 } 227 228 /** 229 * Reset the remaining digests. Note this does *not* reset the number of 230 * digest clones that can be obtained. Digests that have already been 231 * cloned and are gone remain gone. 232 */ 233 void reset() { 234 if (version != -1) { 235 throw new RuntimeException( 236 "reset() can be only be called before protocolDetermined"); 237 } 238 data.reset(); 239 } 240 241 242 void protocolDetermined(ProtocolVersion pv) { 243 244 // Do not set again, will ignore 245 if (version != -1) { 246 return; 247 } 248 249 if (pv.maybeDTLSProtocol()) { 250 version = pv.compareTo(ProtocolVersion.DTLS12) >= 0 ? 2 : 1; 251 } else { 252 version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1; 253 } 254 switch (version) { 255 case 1: 256 // initiate md5, sha and call update on saved array 257 try { 258 md5 = CloneableDigest.getDigest("MD5", clonesNeeded); 259 sha = CloneableDigest.getDigest("SHA", clonesNeeded); 260 } catch (NoSuchAlgorithmException e) { 261 throw new RuntimeException 262 ("Algorithm MD5 or SHA not available", e); 263 } 264 byte[] bytes = data.toByteArray(); 265 update(bytes, 0, bytes.length); 266 break; 267 case 2: 268 break; 269 } 270 } 271 272 ///////////////////////////////////////////////////////////// 273 // Below are old methods for pre-TLS 1.1 274 ///////////////////////////////////////////////////////////// 275 276 /** 277 * Return a new MD5 digest updated with all data hashed so far. 278 */ 279 MessageDigest getMD5Clone() { 280 if (version != 1) { 281 throw new RuntimeException( 282 "getMD5Clone() can be only be called for TLS 1.1"); 283 } 284 return cloneDigest(md5); 285 } 286 287 /** 288 * Return a new SHA digest updated with all data hashed so far. 289 */ 290 MessageDigest getSHAClone() { 291 if (version != 1) { 292 throw new RuntimeException( 293 "getSHAClone() can be only be called for TLS 1.1"); 294 } 295 return cloneDigest(sha); 296 } 297 298 private static MessageDigest cloneDigest(MessageDigest digest) { 299 try { 300 return (MessageDigest)digest.clone(); 301 } catch (CloneNotSupportedException e) { 302 // cannot occur for digests generated via CloneableDigest 303 throw new RuntimeException("Could not clone digest", e); 304 } 305 } 306 307 ///////////////////////////////////////////////////////////// 308 // Below are new methods for TLS 1.2 309 ///////////////////////////////////////////////////////////// 310 311 private static String normalizeAlgName(String alg) { 312 alg = alg.toUpperCase(Locale.US); 313 if (alg.startsWith("SHA")) { 314 if (alg.length() == 3) { 315 return "SHA-1"; 316 } 317 if (alg.charAt(3) != '-') { 318 return "SHA-" + alg.substring(3); 319 } 320 } 321 return alg; 322 } 323 /** 324 * Specifies the hash algorithm used in Finished. This should be called 325 * based in info in ServerHello. 326 * Can be called multiple times. 327 */ 328 void setFinishedAlg(String s) { 329 if (s == null) { 330 throw new RuntimeException( 331 "setFinishedAlg's argument cannot be null"); 332 } 333 334 // Can be called multiple times, but only set once 335 if (finMD != null) return; 336 337 try { 338 finMD = CloneableDigest.getDigest(normalizeAlgName(s), 2); 339 } catch (NoSuchAlgorithmException e) { 340 throw new Error(e); 341 } 342 finMD.update(data.toByteArray()); 343 } 344 345 byte[] getAllHandshakeMessages() { 346 return data.toByteArray(); 347 } 348 349 /** 350 * Calculates the hash in Finished. Must be called after setFinishedAlg(). 351 * This method can be called twice, for Finished messages of the server 352 * side and client side respectively. 353 */ 354 byte[] getFinishedHash() { 355 try { 356 return cloneDigest(finMD).digest(); 357 } catch (Exception e) { 358 throw new Error("Error during hash calculation", e); 359 } 360 } 361} 362 363/** 364 * A wrapper for MessageDigests that simulates cloning of non-cloneable 365 * digests. It uses the standard MessageDigest API and therefore can be used 366 * transparently in place of a regular digest. 367 * 368 * Note that we extend the MessageDigest class directly rather than 369 * MessageDigestSpi. This works because MessageDigest was originally designed 370 * this way in the JDK 1.1 days which allows us to avoid creating an internal 371 * provider. 372 * 373 * It can be "cloned" a limited number of times, which is specified at 374 * construction time. This is achieved by internally maintaining n digests 375 * in parallel. Consequently, it is only 1/n-th times as fast as the original 376 * digest. 377 * 378 * Example: 379 * MessageDigest md = CloneableDigest.getDigest("SHA", 2); 380 * md.update(data1); 381 * MessageDigest md2 = (MessageDigest)md.clone(); 382 * md2.update(data2); 383 * byte[] d1 = md2.digest(); // digest of data1 || data2 384 * md.update(data3); 385 * byte[] d2 = md.digest(); // digest of data1 || data3 386 * 387 * This class is not thread safe. 388 * 389 */ 390final class CloneableDigest extends MessageDigest implements Cloneable { 391 392 /** 393 * The individual MessageDigests. Initially, all elements are non-null. 394 * When clone() is called, the non-null element with the maximum index is 395 * returned and the array element set to null. 396 * 397 * All non-null element are always in the same state. 398 */ 399 private final MessageDigest[] digests; 400 401 private CloneableDigest(MessageDigest digest, int n, String algorithm) 402 throws NoSuchAlgorithmException { 403 super(algorithm); 404 digests = new MessageDigest[n]; 405 digests[0] = digest; 406 for (int i = 1; i < n; i++) { 407 digests[i] = JsseJce.getMessageDigest(algorithm); 408 } 409 } 410 411 /** 412 * Return a MessageDigest for the given algorithm that can be cloned the 413 * specified number of times. If the default implementation supports 414 * cloning, it is returned. Otherwise, an instance of this class is 415 * returned. 416 */ 417 static MessageDigest getDigest(String algorithm, int n) 418 throws NoSuchAlgorithmException { 419 MessageDigest digest = JsseJce.getMessageDigest(algorithm); 420 try { 421 digest.clone(); 422 // already cloneable, use it 423 return digest; 424 } catch (CloneNotSupportedException e) { 425 return new CloneableDigest(digest, n, algorithm); 426 } 427 } 428 429 /** 430 * Check if this object is still usable. If it has already been cloned the 431 * maximum number of times, there are no digests left and this object can no 432 * longer be used. 433 */ 434 private void checkState() { 435 // XXX handshaking currently doesn't stop updating hashes... 436 // if (digests[0] == null) { 437 // throw new IllegalStateException("no digests left"); 438 // } 439 } 440 441 @Override 442 protected int engineGetDigestLength() { 443 checkState(); 444 return digests[0].getDigestLength(); 445 } 446 447 @Override 448 protected void engineUpdate(byte b) { 449 checkState(); 450 for (int i = 0; (i < digests.length) && (digests[i] != null); i++) { 451 digests[i].update(b); 452 } 453 } 454 455 @Override 456 protected void engineUpdate(byte[] b, int offset, int len) { 457 checkState(); 458 for (int i = 0; (i < digests.length) && (digests[i] != null); i++) { 459 digests[i].update(b, offset, len); 460 } 461 } 462 463 @Override 464 protected byte[] engineDigest() { 465 checkState(); 466 byte[] digest = digests[0].digest(); 467 digestReset(); 468 return digest; 469 } 470 471 @Override 472 protected int engineDigest(byte[] buf, int offset, int len) 473 throws DigestException { 474 checkState(); 475 int n = digests[0].digest(buf, offset, len); 476 digestReset(); 477 return n; 478 } 479 480 /** 481 * Reset all digests after a digest() call. digests[0] has already been 482 * implicitly reset by the digest() call and does not need to be reset 483 * again. 484 */ 485 private void digestReset() { 486 for (int i = 1; (i < digests.length) && (digests[i] != null); i++) { 487 digests[i].reset(); 488 } 489 } 490 491 @Override 492 protected void engineReset() { 493 checkState(); 494 for (int i = 0; (i < digests.length) && (digests[i] != null); i++) { 495 digests[i].reset(); 496 } 497 } 498 499 @Override 500 public Object clone() { 501 checkState(); 502 for (int i = digests.length - 1; i >= 0; i--) { 503 if (digests[i] != null) { 504 MessageDigest digest = digests[i]; 505 digests[i] = null; 506 return digest; 507 } 508 } 509 // cannot occur 510 throw new InternalError(); 511 } 512 513} 514