InputRecord.java revision 12745:f068a4ffddd2
1/* 2 * Copyright (c) 1996, 2014, 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 26package sun.security.ssl; 27 28import java.io.*; 29import java.nio.*; 30import java.util.*; 31 32import javax.crypto.BadPaddingException; 33 34import javax.net.ssl.*; 35 36import sun.misc.HexDumpEncoder; 37 38 39/** 40 * {@code InputRecord} takes care of the management of SSL/TLS/DTLS input 41 * records, including buffering, decryption, handshake messages marshal, etc. 42 * 43 * @author David Brownell 44 */ 45class InputRecord implements Record, Closeable { 46 47 /* Class and subclass dynamic debugging support */ 48 static final Debug debug = Debug.getInstance("ssl"); 49 50 Authenticator readAuthenticator; 51 CipherBox readCipher; 52 53 HandshakeHash handshakeHash; 54 boolean isClosed; 55 56 // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello 57 // and the first message we read is a ClientHello in V2 format, we convert 58 // it to V3. Otherwise we throw an exception when encountering a V2 hello. 59 ProtocolVersion helloVersion; 60 61 // fragment size 62 int fragmentSize; 63 64 InputRecord() { 65 this.readCipher = CipherBox.NULL; 66 this.readAuthenticator = null; // Please override this assignment. 67 this.helloVersion = ProtocolVersion.DEFAULT_HELLO; 68 this.fragmentSize = Record.maxDataSize; 69 } 70 71 void setHelloVersion(ProtocolVersion helloVersion) { 72 this.helloVersion = helloVersion; 73 } 74 75 ProtocolVersion getHelloVersion() { 76 return helloVersion; 77 } 78 79 /* 80 * Set instance for the computation of handshake hashes. 81 * 82 * For handshaking, we need to be able to hash every byte above the 83 * record marking layer. This is where we're guaranteed to see those 84 * bytes, so this is where we can hash them ... especially in the 85 * case of hashing the initial V2 message! 86 */ 87 void setHandshakeHash(HandshakeHash handshakeHash) { 88 if (handshakeHash != null) { 89 byte[] reserved = null; 90 if (this.handshakeHash != null) { 91 reserved = this.handshakeHash.getAllHandshakeMessages(); 92 } 93 if ((reserved != null) && (reserved.length != 0)) { 94 handshakeHash.update(reserved, 0, reserved.length); 95 96 if (debug != null && Debug.isOn("data")) { 97 Debug.printHex( 98 "[reserved] handshake hash: len = " + reserved.length, 99 reserved); 100 } 101 } 102 } 103 104 this.handshakeHash = handshakeHash; 105 } 106 107 boolean seqNumIsHuge() { 108 return (readAuthenticator != null) && 109 readAuthenticator.seqNumIsHuge(); 110 } 111 112 boolean isEmpty() { 113 return false; 114 } 115 116 // apply to DTLS SSLEngine 117 void expectingFinishFlight() { 118 // blank 119 } 120 121 /** 122 * Prevent any more data from being read into this record, 123 * and flag the record as holding no data. 124 */ 125 @Override 126 public synchronized void close() throws IOException { 127 if (!isClosed) { 128 isClosed = true; 129 readCipher.dispose(); 130 } 131 } 132 133 // apply to SSLSocket and SSLEngine 134 void changeReadCiphers( 135 Authenticator readAuthenticator, CipherBox readCipher) { 136 137 /* 138 * Dispose of any intermediate state in the underlying cipher. 139 * For PKCS11 ciphers, this will release any attached sessions, 140 * and thus make finalization faster. 141 * 142 * Since MAC's doFinal() is called for every SSL/TLS packet, it's 143 * not necessary to do the same with MAC's. 144 */ 145 readCipher.dispose(); 146 147 this.readAuthenticator = readAuthenticator; 148 this.readCipher = readCipher; 149 } 150 151 // change fragment size 152 void changeFragmentSize(int fragmentSize) { 153 this.fragmentSize = fragmentSize; 154 } 155 156 /* 157 * Check if there is enough inbound data in the ByteBuffer to make 158 * a inbound packet. 159 * 160 * @return -1 if there are not enough bytes to tell (small header), 161 */ 162 // apply to SSLEngine only 163 int bytesInCompletePacket(ByteBuffer buf) throws SSLException { 164 throw new UnsupportedOperationException(); 165 } 166 167 // apply to SSLSocket only 168 int bytesInCompletePacket(InputStream is) throws IOException { 169 throw new UnsupportedOperationException(); 170 } 171 172 /** 173 * Return true if the specified record protocol version is out of the 174 * range of the possible supported versions. 175 */ 176 void checkRecordVersion(ProtocolVersion version, 177 boolean allowSSL20Hello) throws SSLException { 178 // blank 179 } 180 181 // apply to DTLS SSLEngine only 182 Plaintext acquirePlaintext() 183 throws IOException, BadPaddingException { 184 throw new UnsupportedOperationException(); 185 } 186 187 // read, decrypt and decompress the network record. 188 // 189 // apply to SSLEngine only 190 Plaintext decode(ByteBuffer netData) 191 throws IOException, BadPaddingException { 192 throw new UnsupportedOperationException(); 193 } 194 195 // apply to SSLSocket only 196 Plaintext decode(InputStream is, ByteBuffer destination) 197 throws IOException, BadPaddingException { 198 throw new UnsupportedOperationException(); 199 } 200 201 // apply to SSLSocket only 202 void setDeliverStream(OutputStream outputStream) { 203 throw new UnsupportedOperationException(); 204 } 205 206 // calculate plaintext fragment size 207 // 208 // apply to SSLEngine only 209 int estimateFragmentSize(int packetSize) { 210 throw new UnsupportedOperationException(); 211 } 212 213 // 214 // shared helpers 215 // 216 217 // Not apply to DTLS 218 static ByteBuffer convertToClientHello(ByteBuffer packet) { 219 220 int srcPos = packet.position(); 221 int srcLim = packet.limit(); 222 223 byte firstByte = packet.get(); 224 byte secondByte = packet.get(); 225 int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2; 226 227 packet.position(srcPos + 3); // the V2ClientHello record header 228 229 byte majorVersion = packet.get(); 230 byte minorVersion = packet.get(); 231 232 int cipherSpecLen = ((packet.get() & 0xFF) << 8) + 233 (packet.get() & 0xFF); 234 int sessionIdLen = ((packet.get() & 0xFF) << 8) + 235 (packet.get() & 0xFF); 236 int nonceLen = ((packet.get() & 0xFF) << 8) + 237 (packet.get() & 0xFF); 238 239 // Required space for the target SSLv3 ClientHello message. 240 // 5: record header size 241 // 4: handshake header size 242 // 2: ClientHello.client_version 243 // 32: ClientHello.random 244 // 1: length byte of ClientHello.session_id 245 // 2: empty ClientHello.compression_methods 246 int requiredSize = 46 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 ); 247 byte[] converted = new byte[requiredSize]; 248 249 /* 250 * Build the first part of the V3 record header from the V2 one 251 * that's now buffered up. (Lengths are fixed up later). 252 */ 253 // Note: need not to set the header actually. 254 converted[0] = ct_handshake; 255 converted[1] = majorVersion; 256 converted[2] = minorVersion; 257 // header [3..4] for handshake message length 258 // required size is 5; 259 260 /* 261 * Store the generic V3 handshake header: 4 bytes 262 */ 263 converted[5] = 1; // HandshakeMessage.ht_client_hello 264 // buf [6..8] for length of ClientHello (int24) 265 // required size += 4; 266 267 /* 268 * ClientHello header starts with SSL version 269 */ 270 converted[9] = majorVersion; 271 converted[10] = minorVersion; 272 // required size += 2; 273 int pointer = 11; 274 275 /* 276 * Copy Random value/nonce ... if less than the 32 bytes of 277 * a V3 "Random", right justify and zero pad to the left. Else 278 * just take the last 32 bytes. 279 */ 280 int offset = srcPos + 11 + cipherSpecLen + sessionIdLen; 281 282 if (nonceLen < 32) { 283 for (int i = 0; i < (32 - nonceLen); i++) { 284 converted[pointer++] = 0; 285 } 286 packet.position(offset); 287 packet.get(converted, pointer, nonceLen); 288 289 pointer += nonceLen; 290 } else { 291 packet.position(offset + nonceLen - 32); 292 packet.get(converted, pointer, 32); 293 294 pointer += 32; 295 } 296 297 /* 298 * Copy session ID (only one byte length!) 299 */ 300 offset -= sessionIdLen; 301 converted[pointer++] = (byte)(sessionIdLen & 0xFF); 302 packet.position(offset); 303 packet.get(converted, pointer, sessionIdLen); 304 305 /* 306 * Copy and translate cipher suites ... V2 specs with first byte zero 307 * are really V3 specs (in the last 2 bytes), just copy those and drop 308 * the other ones. Preference order remains unchanged. 309 * 310 * Example: Netscape Navigator 3.0 (exportable) says: 311 * 312 * 0/3, SSL_RSA_EXPORT_WITH_RC4_40_MD5 313 * 0/6, SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 314 * 315 * Microsoft Internet Explorer 3.0 (exportable) supports only 316 * 317 * 0/3, SSL_RSA_EXPORT_WITH_RC4_40_MD5 318 */ 319 int j; 320 321 offset -= cipherSpecLen; 322 packet.position(offset); 323 324 j = pointer + 2; 325 for (int i = 0; i < cipherSpecLen; i += 3) { 326 if (packet.get() != 0) { 327 // Ignore version 2.0 specifix cipher suite. Clients 328 // should also include the version 3.0 equivalent in 329 // the V2ClientHello message. 330 packet.get(); // ignore the 2nd byte 331 packet.get(); // ignore the 3rd byte 332 continue; 333 } 334 335 converted[j++] = packet.get(); 336 converted[j++] = packet.get(); 337 } 338 339 j -= pointer + 2; 340 converted[pointer++] = (byte)((j >>> 8) & 0xFF); 341 converted[pointer++] = (byte)(j & 0xFF); 342 pointer += j; 343 344 /* 345 * Append compression methods (default/null only) 346 */ 347 converted[pointer++] = 1; 348 converted[pointer++] = 0; // Session.compression_null 349 350 /* 351 * Fill in lengths of the messages we synthesized (nested: 352 * V3 handshake message within V3 record). 353 */ 354 // Note: need not to set the header actually. 355 int fragLen = pointer - 5; // TLSPlaintext.length 356 converted[3] = (byte)((fragLen >>> 8) & 0xFF); 357 converted[4] = (byte)(fragLen & 0xFF); 358 359 /* 360 * Handshake.length, length of ClientHello message 361 */ 362 fragLen = pointer - 9; // Handshake.length 363 converted[6] = (byte)((fragLen >>> 16) & 0xFF); 364 converted[7] = (byte)((fragLen >>> 8) & 0xFF); 365 converted[8] = (byte)(fragLen & 0xFF); 366 367 // consume the full record 368 packet.position(srcPos + recordLen); 369 370 // Need no header bytes. 371 return ByteBuffer.wrap(converted, 5, pointer - 5); // 5: header size 372 } 373 374 static ByteBuffer decrypt(Authenticator authenticator, CipherBox box, 375 byte contentType, ByteBuffer bb) throws BadPaddingException { 376 377 return decrypt(authenticator, box, contentType, bb, null); 378 } 379 380 static ByteBuffer decrypt(Authenticator authenticator, 381 CipherBox box, byte contentType, ByteBuffer bb, 382 byte[] sequence) throws BadPaddingException { 383 384 BadPaddingException reservedBPE = null; 385 int tagLen = 386 (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0; 387 int cipheredLength = bb.remaining(); 388 int srcPos = bb.position(); 389 if (!box.isNullCipher()) { 390 try { 391 // apply explicit nonce for AEAD/CBC cipher suites if needed 392 int nonceSize = box.applyExplicitNonce( 393 authenticator, contentType, bb, sequence); 394 395 // decrypt the content 396 if (box.isAEADMode()) { 397 // DON'T decrypt the nonce_explicit for AEAD mode 398 bb.position(srcPos + nonceSize); 399 } // The explicit IV for CBC mode can be decrypted. 400 401 // Note that the CipherBox.decrypt() does not change 402 // the capacity of the buffer. 403 box.decrypt(bb, tagLen); 404 // We don't actually remove the nonce. 405 bb.position(srcPos + nonceSize); 406 } catch (BadPaddingException bpe) { 407 // RFC 2246 states that decryption_failed should be used 408 // for this purpose. However, that allows certain attacks, 409 // so we just send bad record MAC. We also need to make 410 // sure to always check the MAC to avoid a timing attack 411 // for the same issue. See paper by Vaudenay et al and the 412 // update in RFC 4346/5246. 413 // 414 // Failover to message authentication code checking. 415 reservedBPE = bpe; 416 } 417 } 418 419 // Requires message authentication code for null, stream and block 420 // cipher suites. 421 if ((authenticator instanceof MAC) && (tagLen != 0)) { 422 MAC signer = (MAC)authenticator; 423 int contentLen = bb.remaining() - tagLen; 424 425 // Note that although it is not necessary, we run the same MAC 426 // computation and comparison on the payload for both stream 427 // cipher and CBC block cipher. 428 if (contentLen < 0) { 429 // negative data length, something is wrong 430 if (reservedBPE == null) { 431 reservedBPE = new BadPaddingException("bad record"); 432 } 433 434 // set offset of the dummy MAC 435 contentLen = cipheredLength - tagLen; 436 bb.limit(srcPos + cipheredLength); 437 } 438 439 // Run MAC computation and comparison on the payload. 440 // 441 // MAC data would be stripped off during the check. 442 if (checkMacTags(contentType, bb, signer, sequence, false)) { 443 if (reservedBPE == null) { 444 reservedBPE = new BadPaddingException("bad record MAC"); 445 } 446 } 447 448 // Run MAC computation and comparison on the remainder. 449 // 450 // It is only necessary for CBC block cipher. It is used to get a 451 // constant time of MAC computation and comparison on each record. 452 if (box.isCBCMode()) { 453 int remainingLen = calculateRemainingLen( 454 signer, cipheredLength, contentLen); 455 456 // NOTE: remainingLen may be bigger (less than 1 block of the 457 // hash algorithm of the MAC) than the cipheredLength. 458 // 459 // Is it possible to use a static buffer, rather than allocate 460 // it dynamically? 461 remainingLen += signer.MAClen(); 462 ByteBuffer temporary = ByteBuffer.allocate(remainingLen); 463 464 // Won't need to worry about the result on the remainder. And 465 // then we won't need to worry about what's actual data to 466 // check MAC tag on. We start the check from the header of the 467 // buffer so that we don't need to construct a new byte buffer. 468 checkMacTags(contentType, temporary, signer, sequence, true); 469 } 470 } 471 472 // Is it a failover? 473 if (reservedBPE != null) { 474 throw reservedBPE; 475 } 476 477 return bb.slice(); 478 } 479 480 /* 481 * Run MAC computation and comparison 482 * 483 */ 484 private static boolean checkMacTags(byte contentType, ByteBuffer bb, 485 MAC signer, byte[] sequence, boolean isSimulated) { 486 487 int tagLen = signer.MAClen(); 488 int position = bb.position(); 489 int lim = bb.limit(); 490 int macOffset = lim - tagLen; 491 492 bb.limit(macOffset); 493 byte[] hash = signer.compute(contentType, bb, sequence, isSimulated); 494 if (hash == null || tagLen != hash.length) { 495 // Something is wrong with MAC implementation. 496 throw new RuntimeException("Internal MAC error"); 497 } 498 499 bb.position(macOffset); 500 bb.limit(lim); 501 try { 502 int[] results = compareMacTags(bb, hash); 503 return (results[0] != 0); 504 } finally { 505 // reset to the data 506 bb.position(position); 507 bb.limit(macOffset); 508 } 509 } 510 511 /* 512 * A constant-time comparison of the MAC tags. 513 * 514 * Please DON'T change the content of the ByteBuffer parameter! 515 */ 516 private static int[] compareMacTags(ByteBuffer bb, byte[] tag) { 517 518 // An array of hits is used to prevent Hotspot optimization for 519 // the purpose of a constant-time check. 520 int[] results = {0, 0}; // {missed #, matched #} 521 522 // The caller ensures there are enough bytes available in the buffer. 523 // So we won't need to check the remaining of the buffer. 524 for (int i = 0; i < tag.length; i++) { 525 if (bb.get() != tag[i]) { 526 results[0]++; // mismatched bytes 527 } else { 528 results[1]++; // matched bytes 529 } 530 } 531 532 return results; 533 } 534 535 /* 536 * Run MAC computation and comparison 537 * 538 * Please DON'T change the content of the byte buffer parameter! 539 */ 540 private static boolean checkMacTags(byte contentType, byte[] buffer, 541 int offset, int contentLen, MAC signer, boolean isSimulated) { 542 543 int tagLen = signer.MAClen(); 544 byte[] hash = signer.compute( 545 contentType, buffer, offset, contentLen, isSimulated); 546 if (hash == null || tagLen != hash.length) { 547 // Something is wrong with MAC implementation. 548 throw new RuntimeException("Internal MAC error"); 549 } 550 551 int[] results = compareMacTags(buffer, offset + contentLen, hash); 552 return (results[0] != 0); 553 } 554 555 /* 556 * A constant-time comparison of the MAC tags. 557 * 558 * Please DON'T change the content of the byte buffer parameter! 559 */ 560 private static int[] compareMacTags( 561 byte[] buffer, int offset, byte[] tag) { 562 563 // An array of hits is used to prevent Hotspot optimization for 564 // the purpose of a constant-time check. 565 int[] results = {0, 0}; // {missed #, matched #} 566 567 // The caller ensures there are enough bytes available in the buffer. 568 // So we won't need to check the length of the buffer. 569 for (int i = 0; i < tag.length; i++) { 570 if (buffer[offset + i] != tag[i]) { 571 results[0]++; // mismatched bytes 572 } else { 573 results[1]++; // matched bytes 574 } 575 } 576 577 return results; 578 } 579 580 /* 581 * Calculate the length of a dummy buffer to run MAC computation 582 * and comparison on the remainder. 583 * 584 * The caller MUST ensure that the fullLen is not less than usedLen. 585 */ 586 private static int calculateRemainingLen( 587 MAC signer, int fullLen, int usedLen) { 588 589 int blockLen = signer.hashBlockLen(); 590 int minimalPaddingLen = signer.minimalPaddingLen(); 591 592 // (blockLen - minimalPaddingLen) is the maximum message size of 593 // the last block of hash function operation. See FIPS 180-4, or 594 // MD5 specification. 595 fullLen += 13 - (blockLen - minimalPaddingLen); 596 usedLen += 13 - (blockLen - minimalPaddingLen); 597 598 // Note: fullLen is always not less than usedLen, and blockLen 599 // is always bigger than minimalPaddingLen, so we don't worry 600 // about negative values. 0x01 is added to the result to ensure 601 // that the return value is positive. The extra one byte does 602 // not impact the overall MAC compression function evaluations. 603 return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) - 604 Math.ceil(usedLen/(1.0d * blockLen))) * blockLen; 605 } 606} 607 608