1 /* 2 * Copyright (c) 2015, 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 package sun.security.ssl; 27 28 import java.io.*; 29 import java.nio.*; 30 import java.util.*; 31 import javax.crypto.BadPaddingException; 32 33 import javax.net.ssl.*; 34 35 import sun.misc.HexDumpEncoder; 36 import static sun.security.ssl.HandshakeMessage.*; 37 38 /** 39 * DTLS {@code InputRecord} implementation for {@code SSLEngine}. 40 */ 41 final class DTLSInputRecord extends InputRecord implements DTLSRecord { 42 43 private DTLSReassembler reassembler = null; 44 45 // Cache the session identifier for the detection of session-resuming 46 // handshake. 47 byte[] prevSessionID = new byte[0]; 48 49 int readEpoch; 50 51 int prevReadEpoch; 52 Authenticator prevReadAuthenticator; 53 CipherBox prevReadCipher; 54 55 DTLSInputRecord() { 56 this.readEpoch = 0; 57 this.readAuthenticator = new MAC(true); 58 59 this.prevReadEpoch = 0; 60 this.prevReadCipher = CipherBox.NULL; 61 this.prevReadAuthenticator = new MAC(true); 62 } 63 64 @Override 65 void changeReadCiphers(Authenticator readAuthenticator, 66 CipherBox readCipher) { 67 68 prevReadCipher.dispose(); 69 70 this.prevReadAuthenticator = this.readAuthenticator; 71 this.prevReadCipher = this.readCipher; 72 this.prevReadEpoch = this.readEpoch; 73 74 this.readAuthenticator = readAuthenticator; 75 this.readCipher = readCipher; 76 this.readEpoch++; 77 } 78 79 @Override 80 synchronized public void close() throws IOException { 81 if (!isClosed) { 82 prevReadCipher.dispose(); 83 super.close(); 84 } 85 } 86 87 @Override 88 boolean isEmpty() { 89 return ((reassembler == null) || reassembler.isEmpty()); 90 } 91 92 @Override 93 int estimateFragmentSize(int packetSize) { 94 int macLen = 0; 95 if (readAuthenticator instanceof MAC) { 96 macLen = ((MAC)readAuthenticator).MAClen(); 97 } 98 99 if (packetSize > 0) { 100 return readCipher.estimateFragmentSize( 101 packetSize, macLen, headerSize); 102 } else { 103 return Record.maxDataSize; 104 } 105 } 106 107 @Override 108 void expectingFinishFlight() { 109 if (reassembler != null) { 110 reassembler.expectingFinishFlight(); 111 } 112 } 113 114 @Override 115 Plaintext acquirePlaintext() { 116 if (reassembler != null) { 117 Plaintext plaintext = reassembler.acquirePlaintext(); 118 if (reassembler.finished()) { 119 // discard all buffered unused message. 120 reassembler = null; 121 } 122 123 return plaintext; 124 } 125 126 return null; 127 } 128 129 @Override 130 Plaintext decode(ByteBuffer packet) { 131 132 if (isClosed) { 133 return null; 134 } 135 136 if (debug != null && Debug.isOn("packet")) { 137 Debug.printHex( 138 "[Raw read]: length = " + packet.remaining(), packet); 139 } 140 141 // The caller should have validated the record. 142 int srcPos = packet.position(); 143 int srcLim = packet.limit(); 144 145 byte contentType = packet.get(); // pos: 0 146 byte majorVersion = packet.get(); // pos: 1 147 byte minorVersion = packet.get(); // pos: 2 148 byte[] recordEnS = new byte[8]; // epoch + seqence 149 packet.get(recordEnS); 150 int recordEpoch = ((recordEnS[0] & 0xFF) << 8) | 151 (recordEnS[1] & 0xFF); // pos: 3, 4 152 long recordSeq = Authenticator.toLong(recordEnS); 153 int contentLen = ((packet.get() & 0xFF) << 8) | 154 (packet.get() & 0xFF); // pos: 11, 12 155 156 if (debug != null && Debug.isOn("record")) { 157 System.out.println(Thread.currentThread().getName() + 158 ", READ: " + 159 ProtocolVersion.valueOf(majorVersion, minorVersion) + 160 " " + Record.contentName(contentType) + ", length = " + 161 contentLen); 162 } 163 164 int recLim = srcPos + DTLSRecord.headerSize + contentLen; 165 if (this.readEpoch > recordEpoch) { 166 // Discard old records delivered before this epoch. 167 168 // Reset the position of the packet buffer. 169 packet.position(recLim); 170 return null; 171 } 172 173 if (this.readEpoch < recordEpoch) { 174 if (contentType != Record.ct_handshake) { 175 // just discard it if not a handshake message 176 packet.position(recLim); 177 return null; 178 } 179 180 // Not ready to decrypt this record, may be encrypted Finished 181 // message, need to buffer it. 182 if (reassembler == null) { 183 reassembler = new DTLSReassembler(); 184 } 185 186 byte[] fragment = new byte[contentLen]; 187 packet.get(fragment); // copy the fragment 188 RecordFragment buffered = new RecordFragment(fragment, contentType, 189 majorVersion, minorVersion, 190 recordEnS, recordEpoch, recordSeq, true); 191 192 reassembler.queueUpFragment(buffered); 193 194 // consume the full record in the packet buffer. 195 packet.position(recLim); 196 197 Plaintext plaintext = reassembler.acquirePlaintext(); 198 if (reassembler.finished()) { 199 // discard all buffered unused message. 200 reassembler = null; 201 } 202 203 return plaintext; 204 } 205 206 if (this.readEpoch == recordEpoch) { 207 // decrypt the fragment 208 packet.limit(recLim); 209 packet.position(srcPos + DTLSRecord.headerSize); 210 211 ByteBuffer plaintextFragment; 212 try { 213 plaintextFragment = decrypt(readAuthenticator, 214 readCipher, contentType, packet, recordEnS); 215 } catch (BadPaddingException bpe) { 216 if (debug != null && Debug.isOn("ssl")) { 217 System.out.println(Thread.currentThread().getName() + 218 " discard invalid record: " + bpe); 219 } 220 221 // invalid, discard this record [section 4.1.2.7, RFC 6347] 222 return null; 223 } finally { 224 // comsume a complete record 225 packet.limit(srcLim); 226 packet.position(recLim); 227 } 228 229 if (contentType != Record.ct_change_cipher_spec && 230 contentType != Record.ct_handshake) { // app data or alert 231 // no retransmission 232 return new Plaintext(contentType, majorVersion, minorVersion, 233 recordEpoch, recordSeq, plaintextFragment); 234 } 235 236 if (contentType == Record.ct_change_cipher_spec) { 237 if (reassembler == null) { 238 // handshake has not started, should be an 239 // old handshake message, discard it. 240 return null; 241 } 242 243 reassembler.queueUpFragment( 244 new RecordFragment(plaintextFragment, contentType, 245 majorVersion, minorVersion, 246 recordEnS, recordEpoch, recordSeq, false)); 247 } else { // handshake record 248 // One record may contain 1+ more handshake messages. 249 while (plaintextFragment.remaining() > 0) { 250 251 HandshakeFragment hsFrag = parseHandshakeMessage( 252 contentType, majorVersion, minorVersion, 253 recordEnS, recordEpoch, recordSeq, plaintextFragment); 254 255 if (hsFrag == null) { 256 // invalid, discard this record 257 return null; 258 } 259 260 if ((reassembler == null) && 261 isKickstart(hsFrag.handshakeType)) { 262 reassembler = new DTLSReassembler(); 263 } 264 265 if (reassembler != null) { 266 reassembler.queueUpHandshake(hsFrag); 267 } // else, just ignore the message. 268 } 269 } 270 271 // Completed the read of the full record. Acquire the reassembled 272 // messages. 273 if (reassembler != null) { 274 Plaintext plaintext = reassembler.acquirePlaintext(); 275 if (reassembler.finished()) { 276 // discard all buffered unused message. 277 reassembler = null; 278 } 279 280 return plaintext; 281 } 282 } 283 284 return null; // make the complier happy 285 } 286 287 @Override 288 int bytesInCompletePacket(ByteBuffer packet) throws SSLException { 289 290 // DTLS length field is in bytes 11/12 291 if (packet.remaining() < headerSize) { 292 return -1; 293 } 294 295 // Last sanity check that it's not a wild record 296 int pos = packet.position(); 297 298 // Check the content type of the record. 299 byte contentType = packet.get(pos); 300 if (!Record.isValidContentType(contentType)) { 301 throw new SSLException( 302 "Unrecognized SSL message, plaintext connection?"); 303 } 304 305 // Check the protocol version of the record. 306 ProtocolVersion recordVersion = 307 ProtocolVersion.valueOf(packet.get(pos + 1), packet.get(pos + 2)); 308 checkRecordVersion(recordVersion, false); 309 310 // Get the fragment length of the record. 311 int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) + 312 (packet.get(pos + 12) & 0xFF) + headerSize; 313 if (fragLen > Record.maxFragmentSize) { 314 throw new SSLException( 315 "Record overflow, fragment length (" + fragLen + 316 ") MUST not exceed " + Record.maxFragmentSize); 317 } 318 319 return fragLen; 320 } 321 322 @Override 323 void checkRecordVersion(ProtocolVersion recordVersion, 324 boolean allowSSL20Hello) throws SSLException { 325 326 if (!recordVersion.maybeDTLSProtocol()) { 327 throw new SSLException( 328 "Unrecognized record version " + recordVersion + 329 " , plaintext connection?"); 330 } 331 } 332 333 private static boolean isKickstart(byte handshakeType) { 334 return (handshakeType == HandshakeMessage.ht_client_hello) || 335 (handshakeType == HandshakeMessage.ht_hello_request) || 336 (handshakeType == HandshakeMessage.ht_hello_verify_request); 337 } 338 339 private static HandshakeFragment parseHandshakeMessage( 340 byte contentType, byte majorVersion, byte minorVersion, 341 byte[] recordEnS, int recordEpoch, long recordSeq, 342 ByteBuffer plaintextFragment) { 343 344 int remaining = plaintextFragment.remaining(); 345 if (remaining < handshakeHeaderSize) { 346 if (debug != null && Debug.isOn("ssl")) { 347 System.out.println( 348 Thread.currentThread().getName() + 349 " discard invalid record: " + 350 "too small record to hold a handshake fragment"); 351 } 352 353 // invalid, discard this record [section 4.1.2.7, RFC 6347] 354 return null; 355 } 356 357 byte handshakeType = plaintextFragment.get(); // pos: 0 358 int messageLength = 359 ((plaintextFragment.get() & 0xFF) << 16) | 360 ((plaintextFragment.get() & 0xFF) << 8) | 361 (plaintextFragment.get() & 0xFF); // pos: 1-3 362 int messageSeq = 363 ((plaintextFragment.get() & 0xFF) << 8) | 364 (plaintextFragment.get() & 0xFF); // pos: 4/5 365 int fragmentOffset = 366 ((plaintextFragment.get() & 0xFF) << 16) | 367 ((plaintextFragment.get() & 0xFF) << 8) | 368 (plaintextFragment.get() & 0xFF); // pos: 6-8 369 int fragmentLength = 370 ((plaintextFragment.get() & 0xFF) << 16) | 371 ((plaintextFragment.get() & 0xFF) << 8) | 372 (plaintextFragment.get() & 0xFF); // pos: 9-11 373 if ((remaining - handshakeHeaderSize) < fragmentLength) { 374 if (debug != null && Debug.isOn("ssl")) { 375 System.out.println( 376 Thread.currentThread().getName() + 377 " discard invalid record: " + 378 "not a complete handshake fragment in the record"); 379 } 380 381 // invalid, discard this record [section 4.1.2.7, RFC 6347] 382 return null; 383 } 384 385 byte[] fragment = new byte[fragmentLength]; 386 plaintextFragment.get(fragment); 387 388 return new HandshakeFragment(fragment, contentType, 389 majorVersion, minorVersion, 390 recordEnS, recordEpoch, recordSeq, 391 handshakeType, messageLength, 392 messageSeq, fragmentOffset, fragmentLength); 393 } 394 395 // buffered record fragment 396 private static class RecordFragment implements Comparable<RecordFragment> { 397 boolean isCiphertext; 398 399 byte contentType; 400 byte majorVersion; 401 byte minorVersion; 402 int recordEpoch; 403 long recordSeq; 404 byte[] recordEnS; 405 byte[] fragment; 406 407 RecordFragment(ByteBuffer fragBuf, byte contentType, 408 byte majorVersion, byte minorVersion, byte[] recordEnS, 409 int recordEpoch, long recordSeq, boolean isCiphertext) { 410 this((byte[])null, contentType, majorVersion, minorVersion, 411 recordEnS, recordEpoch, recordSeq, isCiphertext); 412 413 this.fragment = new byte[fragBuf.remaining()]; 414 fragBuf.get(this.fragment); 415 } 416 417 RecordFragment(byte[] fragment, byte contentType, 418 byte majorVersion, byte minorVersion, byte[] recordEnS, 419 int recordEpoch, long recordSeq, boolean isCiphertext) { 420 this.isCiphertext = isCiphertext; 421 422 this.contentType = contentType; 423 this.majorVersion = majorVersion; 424 this.minorVersion = minorVersion; 425 this.recordEpoch = recordEpoch; 426 this.recordSeq = recordSeq; 427 this.recordEnS = recordEnS; 428 this.fragment = fragment; // The caller should have cloned 429 // the buffer if necessary. 430 } 431 432 @Override 433 public int compareTo(RecordFragment o) { 434 return Long.compareUnsigned(this.recordSeq, o.recordSeq); 435 } 436 } 437 438 // buffered handshake message 439 private static final class HandshakeFragment extends RecordFragment { 440 441 byte handshakeType; // handshake msg_type 442 int messageSeq; // message_seq 443 int messageLength; // Handshake body length 444 int fragmentOffset; // fragment_offset 445 int fragmentLength; // fragment_length 446 447 HandshakeFragment(byte[] fragment, byte contentType, 448 byte majorVersion, byte minorVersion, byte[] recordEnS, 449 int recordEpoch, long recordSeq, 450 byte handshakeType, int messageLength, 451 int messageSeq, int fragmentOffset, int fragmentLength) { 452 453 super(fragment, contentType, majorVersion, minorVersion, 454 recordEnS, recordEpoch , recordSeq, false); 455 456 this.handshakeType = handshakeType; 457 this.messageSeq = messageSeq; 458 this.messageLength = messageLength; 459 this.fragmentOffset = fragmentOffset; 460 this.fragmentLength = fragmentLength; 461 } 462 463 @Override 464 public int compareTo(RecordFragment o) { 465 if (o instanceof HandshakeFragment) { 466 HandshakeFragment other = (HandshakeFragment)o; 467 if (this.messageSeq != other.messageSeq) { 468 // keep the insertion order for the same message 469 return this.messageSeq - other.messageSeq; 470 } 471 } 472 473 return Long.compareUnsigned(this.recordSeq, o.recordSeq); 474 } 475 } 476 477 private static final class HoleDescriptor { 478 int offset; // fragment_offset 479 int limit; // fragment_offset + fragment_length 480 481 HoleDescriptor(int offset, int limit) { 482 this.offset = offset; 483 this.limit = limit; 484 } 485 } 486 487 final class DTLSReassembler { 488 TreeSet<RecordFragment> bufferedFragments = new TreeSet<>(); 489 490 HashMap<Byte, List<HoleDescriptor>> holesMap = new HashMap<>(5); 491 492 // Epoch, sequence number and handshake message sequence of the 493 // beginning message of a flight. 494 byte flightType = (byte)0xFF; 495 496 int flightTopEpoch = 0; 497 long flightTopRecordSeq = -1; 498 int flightTopMessageSeq = 0; 499 500 // Epoch, sequence number and handshake message sequence of the 501 // next message acquisition of a flight. 502 int nextRecordEpoch = 0; // next record epoch 503 long nextRecordSeq = 0; // next record sequence number 504 int nextMessageSeq = 0; // next handshake message number 505 506 // Expect ChangeCipherSpec and Finished messages for the final flight. 507 boolean expectCCSFlight = false; 508 509 // Ready to process this flight if received all messages of the flight. 510 boolean flightIsReady = false; 511 boolean needToCheckFlight = false; 512 513 // Is it a session-resuming abbreviated handshake.? 514 boolean isAbbreviatedHandshake = false; 515 516 // The handshke fragment with the biggest record sequence number 517 // in a flight, not counting the Finished message. 518 HandshakeFragment lastHandshakeFragment = null; 519 520 // Is handshake (intput) finished? 521 boolean handshakeFinished = false; 522 523 DTLSReassembler() { 524 // blank 525 } 526 527 boolean finished() { 528 return handshakeFinished; 529 } 530 531 void expectingFinishFlight() { 532 expectCCSFlight = true; 533 } 534 535 void queueUpHandshake(HandshakeFragment hsf) { 536 537 if ((nextRecordEpoch > hsf.recordEpoch) || 538 (nextRecordSeq > hsf.recordSeq) || 539 (nextMessageSeq > hsf.messageSeq)) { 540 // too old, discard this record 541 return; 542 } 543 544 // Is it the first message of next flight? 545 if ((flightTopMessageSeq == hsf.messageSeq) && 546 (hsf.fragmentOffset == 0) && (flightTopRecordSeq == -1)) { 547 548 flightType = hsf.handshakeType; 549 flightTopEpoch = hsf.recordEpoch; 550 flightTopRecordSeq = hsf.recordSeq; 551 552 if (hsf.handshakeType == HandshakeMessage.ht_server_hello) { 553 // Is it a session-resuming handshake? 554 try { 555 isAbbreviatedHandshake = 556 isSessionResuming(hsf.fragment, prevSessionID); 557 } catch (SSLException ssle) { 558 if (debug != null && Debug.isOn("ssl")) { 559 System.out.println( 560 Thread.currentThread().getName() + 561 " discard invalid record: " + ssle); 562 } 563 564 // invalid, discard it [section 4.1.2.7, RFC 6347] 565 return; 566 } 567 568 if (!isAbbreviatedHandshake) { 569 prevSessionID = getSessionID(hsf.fragment); 570 } 571 } 572 } 573 574 boolean fragmented = false; 575 if ((hsf.fragmentOffset) != 0 || 576 (hsf.fragmentLength != hsf.messageLength)) { 577 578 fragmented = true; 579 } 580 581 List<HoleDescriptor> holes = holesMap.get(hsf.handshakeType); 582 if (holes == null) { 583 if (!fragmented) { 584 holes = Collections.emptyList(); 585 } else { 586 holes = new LinkedList<HoleDescriptor>(); 587 holes.add(new HoleDescriptor(0, hsf.messageLength)); 588 } 589 holesMap.put(hsf.handshakeType, holes); 590 } else if (holes.isEmpty()) { 591 // Have got the full handshake message. This record may be 592 // a handshake message retransmission. Discard this record. 593 // 594 // It's OK to discard retransmission as the handshake hash 595 // is computed as if each handshake message had been sent 596 // as a single fragment. 597 // 598 // Note that ClientHello messages are delivered twice in 599 // DTLS handshaking. 600 if ((hsf.handshakeType != HandshakeMessage.ht_client_hello && 601 hsf.handshakeType != ht_hello_verify_request) || 602 (nextMessageSeq != hsf.messageSeq)) { 603 return; 604 } 605 606 if (fragmented) { 607 holes = new LinkedList<HoleDescriptor>(); 608 holes.add(new HoleDescriptor(0, hsf.messageLength)); 609 } 610 holesMap.put(hsf.handshakeType, holes); 611 } 612 613 if (fragmented) { 614 int fragmentLimit = hsf.fragmentOffset + hsf.fragmentLength; 615 for (int i = 0; i < holes.size(); i++) { 616 617 HoleDescriptor hole = holes.get(i); 618 if ((hole.limit <= hsf.fragmentOffset) || 619 (hole.offset >= fragmentLimit)) { 620 // Also discard overlapping handshake retransmissions. 621 continue; 622 } 623 624 // The ranges SHOULD NOT overlap. 625 if (((hole.offset > hsf.fragmentOffset) && 626 (hole.offset < fragmentLimit)) || 627 ((hole.limit > hsf.fragmentOffset) && 628 (hole.limit < fragmentLimit))) { 629 630 if (debug != null && Debug.isOn("ssl")) { 631 System.out.println( 632 Thread.currentThread().getName() + 633 " discard invalid record: " + 634 "handshake fragment ranges are overlapping"); 635 } 636 637 // invalid, discard it [section 4.1.2.7, RFC 6347] 638 return; 639 } 640 641 // This record interacts with this hole, fill the hole. 642 holes.remove(i); 643 // i--; 644 645 if (hsf.fragmentOffset > hole.offset) { 646 holes.add(new HoleDescriptor( 647 hole.offset, hsf.fragmentOffset)); 648 // i++; 649 } 650 651 if (fragmentLimit < hole.limit) { 652 holes.add(new HoleDescriptor( 653 fragmentLimit, hole.limit)); 654 // i++; 655 } 656 657 // As no ranges overlap, no interact with other holes. 658 break; 659 } 660 } 661 662 // append this fragment 663 bufferedFragments.add(hsf); 664 665 if ((lastHandshakeFragment == null) || 666 (lastHandshakeFragment.compareTo(hsf) < 0)) { 667 668 lastHandshakeFragment = hsf; 669 } 670 671 if (flightIsReady) { 672 flightIsReady = false; 673 } 674 needToCheckFlight = true; 675 } 676 677 // queue up change_cipher_spec or encrypted message 678 void queueUpFragment(RecordFragment rf) { 679 if ((nextRecordEpoch > rf.recordEpoch) || 680 (nextRecordSeq > rf.recordSeq)) { 681 // too old, discard this record 682 return; 683 } 684 685 // Is it the first message of next flight? 686 if (expectCCSFlight && 687 (rf.contentType == Record.ct_change_cipher_spec)) { 688 689 flightType = (byte)0xFE; 690 flightTopEpoch = rf.recordEpoch; 691 flightTopRecordSeq = rf.recordSeq; 692 } 693 694 // append this fragment 695 bufferedFragments.add(rf); 696 697 if (flightIsReady) { 698 flightIsReady = false; 699 } 700 needToCheckFlight = true; 701 } 702 703 boolean isEmpty() { 704 return (bufferedFragments.isEmpty() || 705 (!flightIsReady && !needToCheckFlight) || 706 (needToCheckFlight && !flightIsReady())); 707 } 708 709 Plaintext acquirePlaintext() { 710 if (bufferedFragments.isEmpty()) { 711 // reset the flight 712 if (flightIsReady) { 713 flightIsReady = false; 714 needToCheckFlight = false; 715 } 716 717 return null; 718 } 719 720 if (!flightIsReady && needToCheckFlight) { 721 // check the fligth status 722 flightIsReady = flightIsReady(); 723 724 // set for next flight 725 if (flightIsReady) { 726 flightTopMessageSeq = lastHandshakeFragment.messageSeq + 1; 727 flightTopRecordSeq = -1; 728 } 729 730 needToCheckFlight = false; 731 } 732 733 if (!flightIsReady) { 734 return null; 735 } 736 737 RecordFragment rFrag = bufferedFragments.first(); 738 if (!rFrag.isCiphertext) { 739 // handshake message, or ChangeCipherSpec message 740 return acquireHandshakeMessage(); 741 } else { 742 // a Finished message or other ciphertexts 743 return acquireCachedMessage(); 744 } 745 } 746 747 private Plaintext acquireCachedMessage() { 748 749 RecordFragment rFrag = bufferedFragments.first(); 750 if (readEpoch != rFrag.recordEpoch) { 751 if (readEpoch > rFrag.recordEpoch) { 752 // discard old records 753 bufferedFragments.remove(rFrag); // popup the fragment 754 } 755 756 // reset the flight 757 if (flightIsReady) { 758 flightIsReady = false; 759 } 760 return null; 761 } 762 763 bufferedFragments.remove(rFrag); // popup the fragment 764 765 ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment); 766 ByteBuffer plaintextFragment = null; 767 try { 768 plaintextFragment = decrypt(readAuthenticator, readCipher, 769 rFrag.contentType, fragment, rFrag.recordEnS); 770 } catch (BadPaddingException bpe) { 771 if (debug != null && Debug.isOn("ssl")) { 772 System.out.println(Thread.currentThread().getName() + 773 " discard invalid record: " + bpe); 774 } 775 776 // invalid, discard this record [section 4.1.2.7, RFC 6347] 777 return null; 778 } 779 780 // The ciphtext handshake message can only be Finished (the 781 // end of this flight), ClinetHello or HelloRequest (the 782 // beginning of the next flight) message. Need not to check 783 // any ChangeCipherSpec message. 784 if (rFrag.contentType == Record.ct_handshake) { 785 HandshakeFragment finFrag = null; 786 while (plaintextFragment.remaining() > 0) { 787 HandshakeFragment hsFrag = parseHandshakeMessage( 788 rFrag.contentType, 789 rFrag.majorVersion, rFrag.minorVersion, 790 rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq, 791 plaintextFragment); 792 793 if (hsFrag == null) { 794 // invalid, discard this record 795 return null; 796 } 797 798 if (hsFrag.handshakeType == HandshakeMessage.ht_finished) { 799 finFrag = hsFrag; 800 801 // reset for the next flight 802 this.flightType = (byte)0xFF; 803 this.flightTopEpoch = rFrag.recordEpoch; 804 this.flightTopMessageSeq = hsFrag.messageSeq + 1; 805 this.flightTopRecordSeq = -1; 806 } else { 807 // reset the flight 808 if (flightIsReady) { 809 flightIsReady = false; 810 } 811 queueUpHandshake(hsFrag); 812 } 813 } 814 815 this.nextRecordSeq = rFrag.recordSeq + 1; 816 this.nextMessageSeq = 0; 817 818 if (finFrag != null) { 819 this.nextRecordEpoch = finFrag.recordEpoch; 820 this.nextRecordSeq = finFrag.recordSeq + 1; 821 this.nextMessageSeq = finFrag.messageSeq + 1; 822 823 // Finished message does not fragment. 824 byte[] recordFrag = new byte[finFrag.messageLength + 4]; 825 Plaintext plaintext = new Plaintext(finFrag.contentType, 826 finFrag.majorVersion, finFrag.minorVersion, 827 finFrag.recordEpoch, finFrag.recordSeq, 828 ByteBuffer.wrap(recordFrag)); 829 830 // fill the handshake fragment of the record 831 recordFrag[0] = finFrag.handshakeType; 832 recordFrag[1] = 833 (byte)((finFrag.messageLength >>> 16) & 0xFF); 834 recordFrag[2] = 835 (byte)((finFrag.messageLength >>> 8) & 0xFF); 836 recordFrag[3] = (byte)(finFrag.messageLength & 0xFF); 837 838 System.arraycopy(finFrag.fragment, 0, 839 recordFrag, 4, finFrag.fragmentLength); 840 841 // handshake hashing 842 handshakeHashing(finFrag, plaintext); 843 844 // input handshake finished 845 handshakeFinished = true; 846 847 return plaintext; 848 } else { 849 return acquirePlaintext(); 850 } 851 } else { 852 return new Plaintext(rFrag.contentType, 853 rFrag.majorVersion, rFrag.minorVersion, 854 rFrag.recordEpoch, rFrag.recordSeq, 855 plaintextFragment); 856 } 857 } 858 859 private Plaintext acquireHandshakeMessage() { 860 861 RecordFragment rFrag = bufferedFragments.first(); 862 if (rFrag.contentType == Record.ct_change_cipher_spec) { 863 this.nextRecordEpoch = rFrag.recordEpoch + 1; 864 this.nextRecordSeq = 0; 865 // no change on next handshake message sequence number 866 867 bufferedFragments.remove(rFrag); // popup the fragment 868 869 // Reload if this message has been reserved for handshake hash. 870 handshakeHash.reload(); 871 872 return new Plaintext(rFrag.contentType, 873 rFrag.majorVersion, rFrag.minorVersion, 874 rFrag.recordEpoch, rFrag.recordSeq, 875 ByteBuffer.wrap(rFrag.fragment)); 876 } else { // rFrag.contentType == Record.ct_handshake 877 HandshakeFragment hsFrag = (HandshakeFragment)rFrag; 878 if ((hsFrag.messageLength == hsFrag.fragmentLength) && 879 (hsFrag.fragmentOffset == 0)) { // no fragmentation 880 881 bufferedFragments.remove(rFrag); // popup the fragment 882 883 // this.nextRecordEpoch = hsFrag.recordEpoch; 884 this.nextRecordSeq = hsFrag.recordSeq + 1; 885 this.nextMessageSeq = hsFrag.messageSeq + 1; 886 887 // Note: may try to avoid byte array copy in the future. 888 byte[] recordFrag = new byte[hsFrag.messageLength + 4]; 889 Plaintext plaintext = new Plaintext(hsFrag.contentType, 890 hsFrag.majorVersion, hsFrag.minorVersion, 891 hsFrag.recordEpoch, hsFrag.recordSeq, 892 ByteBuffer.wrap(recordFrag)); 893 894 // fill the handshake fragment of the record 895 recordFrag[0] = hsFrag.handshakeType; 896 recordFrag[1] = 897 (byte)((hsFrag.messageLength >>> 16) & 0xFF); 898 recordFrag[2] = 899 (byte)((hsFrag.messageLength >>> 8) & 0xFF); 900 recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF); 901 902 System.arraycopy(hsFrag.fragment, 0, 903 recordFrag, 4, hsFrag.fragmentLength); 904 905 // handshake hashing 906 handshakeHashing(hsFrag, plaintext); 907 908 return plaintext; 909 } else { // fragmented handshake message 910 // the first record 911 // 912 // Note: may try to avoid byte array copy in the future. 913 byte[] recordFrag = new byte[hsFrag.messageLength + 4]; 914 Plaintext plaintext = new Plaintext(hsFrag.contentType, 915 hsFrag.majorVersion, hsFrag.minorVersion, 916 hsFrag.recordEpoch, hsFrag.recordSeq, 917 ByteBuffer.wrap(recordFrag)); 918 919 // fill the handshake fragment of the record 920 recordFrag[0] = hsFrag.handshakeType; 921 recordFrag[1] = 922 (byte)((hsFrag.messageLength >>> 16) & 0xFF); 923 recordFrag[2] = 924 (byte)((hsFrag.messageLength >>> 8) & 0xFF); 925 recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF); 926 927 int msgSeq = hsFrag.messageSeq; 928 long maxRecodeSN = hsFrag.recordSeq; 929 HandshakeFragment hmFrag = hsFrag; 930 do { 931 System.arraycopy(hmFrag.fragment, 0, 932 recordFrag, hmFrag.fragmentOffset + 4, 933 hmFrag.fragmentLength); 934 // popup the fragment 935 bufferedFragments.remove(rFrag); 936 937 if (maxRecodeSN < hmFrag.recordSeq) { 938 maxRecodeSN = hmFrag.recordSeq; 939 } 940 941 // Note: may buffer retransmitted fragments in order to 942 // speed up the reassembly in the future. 943 944 // read the next buffered record 945 if (!bufferedFragments.isEmpty()) { 946 rFrag = bufferedFragments.first(); 947 if (rFrag.contentType != Record.ct_handshake) { 948 break; 949 } else { 950 hmFrag = (HandshakeFragment)rFrag; 951 } 952 } 953 } while (!bufferedFragments.isEmpty() && 954 (msgSeq == hmFrag.messageSeq)); 955 956 // handshake hashing 957 handshakeHashing(hsFrag, plaintext); 958 959 this.nextRecordSeq = maxRecodeSN + 1; 960 this.nextMessageSeq = msgSeq + 1; 961 962 return plaintext; 963 } 964 } 965 } 966 967 boolean flightIsReady() { 968 969 // 970 // the ChangeCipherSpec/Finished flight 971 // 972 if (expectCCSFlight) { 973 // Have the ChangeCipherSpec/Finished messages been received? 974 return hasFinisedMessage(bufferedFragments); 975 } 976 977 if (flightType == (byte)0xFF) { 978 return false; 979 } 980 981 if ((flightType == HandshakeMessage.ht_client_hello) || 982 (flightType == HandshakeMessage.ht_hello_request) || 983 (flightType == HandshakeMessage.ht_hello_verify_request)) { 984 985 // single handshake message flight 986 return hasCompleted(holesMap.get(flightType)); 987 } 988 989 // 990 // the ServerHello flight 991 // 992 if (flightType == HandshakeMessage.ht_server_hello) { 993 // Firstly, check the first flight handshake message. 994 if (!hasCompleted(holesMap.get(flightType))) { 995 return false; 996 } 997 998 // 999 // an abbreviated handshake 1000 // 1001 if (isAbbreviatedHandshake) { 1002 // Ready to use the flight if received the 1003 // ChangeCipherSpec and Finished messages. 1004 return hasFinisedMessage(bufferedFragments); 1005 } 1006 1007 // 1008 // a full handshake 1009 // 1010 if (lastHandshakeFragment.handshakeType != 1011 HandshakeMessage.ht_server_hello_done) { 1012 // Not yet got the final message of the flight. 1013 return false; 1014 } 1015 1016 // Have all handshake message been received? 1017 return hasCompleted(bufferedFragments, 1018 flightTopMessageSeq, lastHandshakeFragment.messageSeq); 1019 } 1020 1021 // 1022 // the ClientKeyExchange flight 1023 // 1024 // Note: need to consider more messages in this flight if 1025 // ht_supplemental_data and ht_certificate_url are 1026 // suppported in the future. 1027 // 1028 if ((flightType == HandshakeMessage.ht_certificate) || 1029 (flightType == HandshakeMessage.ht_client_key_exchange)) { 1030 1031 // Firstly, check the first flight handshake message. 1032 if (!hasCompleted(holesMap.get(flightType))) { 1033 return false; 1034 } 1035 1036 if (!hasFinisedMessage(bufferedFragments)) { 1037 // not yet got the ChangeCipherSpec/Finished messages 1038 return false; 1039 } 1040 1041 if (flightType == HandshakeMessage.ht_client_key_exchange) { 1042 // single handshake message flight 1043 return true; 1044 } 1045 1046 // 1047 // flightType == HandshakeMessage.ht_certificate 1048 // 1049 // We don't support certificates containing fixed 1050 // Diffie-Hellman parameters. Therefore, CertificateVerify 1051 // message is required if client Certificate message presents. 1052 // 1053 if (lastHandshakeFragment.handshakeType != 1054 HandshakeMessage.ht_certificate_verify) { 1055 // Not yet got the final message of the flight. 1056 return false; 1057 } 1058 1059 // Have all handshake message been received? 1060 return hasCompleted(bufferedFragments, 1061 flightTopMessageSeq, lastHandshakeFragment.messageSeq); 1062 } 1063 1064 // 1065 // Otherwise, need to receive more handshake messages. 1066 // 1067 return false; 1068 } 1069 1070 private boolean isSessionResuming( 1071 byte[] fragment, byte[] prevSid) throws SSLException { 1072 1073 // As the first fragment of ServerHello should be big enough 1074 // to hold the session_id field, need not to worry about the 1075 // fragmentation here. 1076 if ((fragment == null) || (fragment.length < 38)) { 1077 // 38: the minimal ServerHello body length 1078 throw new SSLException( 1079 "Invalid ServerHello message: no sufficient data"); 1080 } 1081 1082 int sidLen = fragment[34]; // 34: the length field 1083 if (sidLen > 32) { // opaque SessionID<0..32> 1084 throw new SSLException( 1085 "Invalid ServerHello message: invalid session id"); 1086 } 1087 1088 if (fragment.length < 38 + sidLen) { 1089 throw new SSLException( 1090 "Invalid ServerHello message: no sufficient data"); 1091 } 1092 1093 if (sidLen != 0 && (prevSid.length == sidLen)) { 1094 // may be a session-resuming handshake 1095 for (int i = 0; i < sidLen; i++) { 1096 if (prevSid[i] != fragment[35 + i]) { 1097 // 35: the session identifier 1098 return false; 1099 } 1100 } 1101 1102 return true; 1103 } 1104 1105 return false; 1106 } 1107 1108 private byte[] getSessionID(byte[] fragment) { 1109 // The validity has been checked in the call to isSessionResuming(). 1110 int sidLen = fragment[34]; // 34: the sessionID length field 1111 1112 byte[] temporary = new byte[sidLen]; 1113 System.arraycopy(fragment, 35, temporary, 0, sidLen); 1114 1115 return temporary; 1116 } 1117 1118 // Looking for the ChangeCipherSpec and Finished messages. 1119 // 1120 // As the cached Finished message should be a ciphertext, we don't 1121 // exactly know a ciphertext is a Finished message or not. According 1122 // to the spec of TLS/DTLS handshaking, a Finished message is always 1123 // sent immediately after a ChangeCipherSpec message. The first 1124 // ciphertext handshake message should be the expected Finished message. 1125 private boolean hasFinisedMessage( 1126 Set<RecordFragment> fragments) { 1127 1128 boolean hasCCS = false; 1129 boolean hasFin = false; 1130 for (RecordFragment fragment : fragments) { 1131 if (fragment.contentType == Record.ct_change_cipher_spec) { 1132 if (hasFin) { 1133 return true; 1134 } 1135 hasCCS = true; 1136 } else if (fragment.contentType == Record.ct_handshake) { 1137 // Finished is the first expected message of a new epoch. 1138 if (fragment.isCiphertext) { 1139 if (hasCCS) { 1140 return true; 1141 } 1142 hasFin = true; 1143 } 1144 } 1145 } 1146 1147 return hasFin && hasCCS; 1148 } 1149 1150 private boolean hasCompleted(List<HoleDescriptor> holes) { 1151 if (holes == null) { 1152 // not yet received this kind of handshake message 1153 return false; 1154 } 1155 1156 return holes.isEmpty(); // no fragment hole for complete message 1157 } 1158 1159 private boolean hasCompleted( 1160 Set<RecordFragment> fragments, 1161 int presentMsgSeq, int endMsgSeq) { 1162 1163 // The caller should have checked the completion of the first 1164 // present handshake message. Need not to check it again. 1165 for (RecordFragment rFrag : fragments) { 1166 if ((rFrag.contentType != Record.ct_handshake) || 1167 rFrag.isCiphertext) { 1168 break; 1169 } 1170 1171 HandshakeFragment hsFrag = (HandshakeFragment)rFrag; 1172 if (hsFrag.messageSeq == presentMsgSeq) { 1173 continue; 1174 } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) { 1175 // check the completion of the handshake message 1176 if (!hasCompleted(holesMap.get(hsFrag.handshakeType))) { 1177 return false; 1178 } 1179 1180 presentMsgSeq = hsFrag.messageSeq; 1181 } else { 1182 // not yet got handshake message next to presentMsgSeq 1183 break; 1184 } 1185 } 1186 1187 return (presentMsgSeq >= endMsgSeq); 1188 // false: if not yet got all messages of the flight. 1189 } 1190 1191 private void handshakeHashing( 1192 HandshakeFragment hsFrag, Plaintext plaintext) { 1193 1194 byte hsType = hsFrag.handshakeType; 1195 if ((hsType == HandshakeMessage.ht_hello_request) || 1196 (hsType == HandshakeMessage.ht_hello_verify_request)) { 1197 1198 // omitted from handshake hash computation 1199 return; 1200 } 1201 1202 if ((hsFrag.messageSeq == 0) && 1203 (hsType == HandshakeMessage.ht_client_hello)) { 1204 1205 // omit initial ClientHello message 1206 // 1207 // 4: handshake header 1208 // 2: ClientHello.client_version 1209 // 32: ClientHello.random 1210 int sidLen = plaintext.fragment.get(38); 1211 1212 if (sidLen == 0) { // empty session_id, initial handshake 1213 return; 1214 } 1215 } 1216 1217 // calculate the DTLS header 1218 byte[] temporary = new byte[12]; // 12: handshake header size 1219 1220 // Handshake.msg_type 1221 temporary[0] = hsFrag.handshakeType; 1222 1223 // Handshake.length 1224 temporary[1] = (byte)((hsFrag.messageLength >> 16) & 0xFF); 1225 temporary[2] = (byte)((hsFrag.messageLength >> 8) & 0xFF); 1226 temporary[3] = (byte)(hsFrag.messageLength & 0xFF); 1227 1228 // Handshake.message_seq 1229 temporary[4] = (byte)((hsFrag.messageSeq >> 8) & 0xFF); 1230 temporary[5] = (byte)(hsFrag.messageSeq & 0xFF); 1231 1232 // Handshake.fragment_offset 1233 temporary[6] = 0; 1234 temporary[7] = 0; 1235 temporary[8] = 0; 1236 1237 // Handshake.fragment_length 1238 temporary[9] = temporary[1]; 1239 temporary[10] = temporary[2]; 1240 temporary[11] = temporary[3]; 1241 1242 plaintext.fragment.position(4); // ignore the TLS header 1243 if ((hsType != HandshakeMessage.ht_finished) && 1244 (hsType != HandshakeMessage.ht_certificate_verify)) { 1245 1246 if (handshakeHash == null) { 1247 // used for cache only 1248 handshakeHash = new HandshakeHash(false); 1249 } 1250 handshakeHash.update(temporary, 0, 12); 1251 handshakeHash.update(plaintext.fragment); 1252 } else { 1253 // Reserve until this handshake message has been processed. 1254 if (handshakeHash == null) { 1255 // used for cache only 1256 handshakeHash = new HandshakeHash(false); 1257 } 1258 handshakeHash.reserve(temporary, 0, 12); 1259 handshakeHash.reserve(plaintext.fragment); 1260 } 1261 plaintext.fragment.position(0); // restore the position 1262 } 1263 } 1264 } 1265