1 /* 2 * Copyright (c) 2015, 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 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.security.util.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 int readEpoch; 46 47 int prevReadEpoch; 48 Authenticator prevReadAuthenticator; 49 CipherBox prevReadCipher; 50 51 DTLSInputRecord() { 52 this.readEpoch = 0; 53 this.readAuthenticator = new MAC(true); 54 55 this.prevReadEpoch = 0; 56 this.prevReadCipher = CipherBox.NULL; 57 this.prevReadAuthenticator = new MAC(true); 58 } 59 60 @Override 61 void changeReadCiphers(Authenticator readAuthenticator, 62 CipherBox readCipher) { 63 64 prevReadCipher.dispose(); 65 66 this.prevReadAuthenticator = this.readAuthenticator; 67 this.prevReadCipher = this.readCipher; 68 this.prevReadEpoch = this.readEpoch; 69 70 this.readAuthenticator = readAuthenticator; 71 this.readCipher = readCipher; 72 this.readEpoch++; 73 } 74 75 @Override 76 public synchronized void close() throws IOException { 77 if (!isClosed) { 78 prevReadCipher.dispose(); 79 super.close(); 80 } 81 } 82 83 @Override 84 boolean isEmpty() { 85 return ((reassembler == null) || reassembler.isEmpty()); 86 } 87 88 @Override 89 int estimateFragmentSize(int packetSize) { 90 int macLen = 0; 91 if (readAuthenticator instanceof MAC) { 92 macLen = ((MAC)readAuthenticator).MAClen(); 93 } 94 95 if (packetSize > 0) { 96 return readCipher.estimateFragmentSize( 97 packetSize, macLen, headerSize); 98 } else { 99 return Record.maxDataSize; 100 } 101 } 102 103 @Override 104 void expectingFinishFlight() { 105 if (reassembler != null) { 106 reassembler.expectingFinishFlight(); 107 } 108 } 109 110 @Override 111 Plaintext acquirePlaintext() { 112 if (reassembler != null) { 113 return reassembler.acquirePlaintext(); 114 } 115 116 return null; 117 } 118 119 @Override 120 Plaintext decode(ByteBuffer packet) { 121 122 if (isClosed) { 123 return null; 124 } 125 126 if (debug != null && Debug.isOn("packet")) { 127 Debug.printHex( 128 "[Raw read]: length = " + packet.remaining(), packet); 129 } 130 131 // The caller should have validated the record. 132 int srcPos = packet.position(); 133 int srcLim = packet.limit(); 134 135 byte contentType = packet.get(); // pos: 0 136 byte majorVersion = packet.get(); // pos: 1 137 byte minorVersion = packet.get(); // pos: 2 138 byte[] recordEnS = new byte[8]; // epoch + seqence 139 packet.get(recordEnS); 140 int recordEpoch = ((recordEnS[0] & 0xFF) << 8) | 141 (recordEnS[1] & 0xFF); // pos: 3, 4 142 long recordSeq = ((recordEnS[2] & 0xFFL) << 40) | 143 ((recordEnS[3] & 0xFFL) << 32) | 144 ((recordEnS[4] & 0xFFL) << 24) | 145 ((recordEnS[5] & 0xFFL) << 16) | 146 ((recordEnS[6] & 0xFFL) << 8) | 147 (recordEnS[7] & 0xFFL); // pos: 5-10 148 149 int contentLen = ((packet.get() & 0xFF) << 8) | 150 (packet.get() & 0xFF); // pos: 11, 12 151 152 if (debug != null && Debug.isOn("record")) { 153 Debug.log("READ: " + 154 ProtocolVersion.valueOf(majorVersion, minorVersion) + 155 " " + Record.contentName(contentType) + ", length = " + 156 contentLen); 157 } 158 159 int recLim = srcPos + DTLSRecord.headerSize + contentLen; 160 161 if (this.prevReadEpoch > recordEpoch) { 162 // Reset the position of the packet buffer. 163 packet.position(recLim); 164 if (debug != null && Debug.isOn("record")) { 165 Debug.printHex("READ: discard this old records", recordEnS); 166 } 167 return null; 168 } 169 170 // Buffer next epoch message if necessary. 171 if (this.readEpoch < recordEpoch) { 172 // Discard the record younger than the current epcoh if: 173 // 1. it is not a handshake message, or 174 // 2. it is not of next epoch. 175 if (((contentType != Record.ct_handshake) && 176 (contentType != Record.ct_change_cipher_spec)) || 177 (this.readEpoch < (recordEpoch - 1))) { 178 179 packet.position(recLim); 180 181 if (debug != null && Debug.isOn("verbose")) { 182 Debug.log("Premature record (epoch), discard it."); 183 } 184 185 return null; 186 } 187 188 // Not ready to decrypt this record, may be an encrypted Finished 189 // message, need to buffer it. 190 byte[] fragment = new byte[contentLen]; 191 packet.get(fragment); // copy the fragment 192 RecordFragment buffered = new RecordFragment(fragment, contentType, 193 majorVersion, minorVersion, 194 recordEnS, recordEpoch, recordSeq, true); 195 196 reassembler.queueUpFragment(buffered); 197 198 // consume the full record in the packet buffer. 199 packet.position(recLim); 200 201 return reassembler.acquirePlaintext(); 202 } 203 204 // 205 // Now, the message is of this epoch or the previous epoch. 206 // 207 Authenticator decodeAuthenticator; 208 CipherBox decodeCipher; 209 if (this.readEpoch == recordEpoch) { 210 decodeAuthenticator = readAuthenticator; 211 decodeCipher = readCipher; 212 } else { // prevReadEpoch == recordEpoch 213 decodeAuthenticator = prevReadAuthenticator; 214 decodeCipher = prevReadCipher; 215 } 216 217 // decrypt the fragment 218 packet.limit(recLim); 219 packet.position(srcPos + DTLSRecord.headerSize); 220 221 ByteBuffer plaintextFragment; 222 try { 223 plaintextFragment = decrypt(decodeAuthenticator, 224 decodeCipher, contentType, packet, recordEnS); 225 } catch (BadPaddingException bpe) { 226 if (debug != null && Debug.isOn("ssl")) { 227 Debug.log("Discard invalid record: " + bpe); 228 } 229 230 // invalid, discard this record [section 4.1.2.7, RFC 6347] 231 return null; 232 } finally { 233 // comsume a complete record 234 packet.limit(srcLim); 235 packet.position(recLim); 236 } 237 238 if (contentType != Record.ct_change_cipher_spec && 239 contentType != Record.ct_handshake) { // app data or alert 240 // no retransmission 241 // Cleanup the handshake reassembler if necessary. 242 if ((reassembler != null) && 243 (reassembler.handshakeEpoch < recordEpoch)) { 244 if (debug != null && Debug.isOn("verbose")) { 245 Debug.log("Cleanup the handshake reassembler"); 246 } 247 248 reassembler = null; 249 } 250 251 return new Plaintext(contentType, majorVersion, minorVersion, 252 recordEpoch, Authenticator.toLong(recordEnS), 253 plaintextFragment); 254 } 255 256 if (contentType == Record.ct_change_cipher_spec) { 257 if (reassembler == null) { 258 if (this.readEpoch != recordEpoch) { 259 // handshake has not started, should be an 260 // old handshake message, discard it. 261 262 if (debug != null && Debug.isOn("verbose")) { 263 Debug.log( 264 "Lagging behind ChangeCipherSpec, discard it."); 265 } 266 267 return null; 268 } 269 270 reassembler = new DTLSReassembler(recordEpoch); 271 } 272 273 reassembler.queueUpChangeCipherSpec( 274 new RecordFragment(plaintextFragment, contentType, 275 majorVersion, minorVersion, 276 recordEnS, recordEpoch, recordSeq, false)); 277 } else { // handshake record 278 // One record may contain 1+ more handshake messages. 279 while (plaintextFragment.remaining() > 0) { 280 281 HandshakeFragment hsFrag = parseHandshakeMessage( 282 contentType, majorVersion, minorVersion, 283 recordEnS, recordEpoch, recordSeq, plaintextFragment); 284 285 if (hsFrag == null) { 286 // invalid, discard this record 287 if (debug != null && Debug.isOn("verbose")) { 288 Debug.log("Invalid handshake message, discard it."); 289 } 290 291 return null; 292 } 293 294 if (reassembler == null) { 295 if (this.readEpoch != recordEpoch) { 296 // handshake has not started, should be an 297 // old handshake message, discard it. 298 299 if (debug != null && Debug.isOn("verbose")) { 300 Debug.log( 301 "Lagging behind handshake record, discard it."); 302 } 303 304 return null; 305 } 306 307 reassembler = new DTLSReassembler(recordEpoch); 308 } 309 310 reassembler.queueUpHandshake(hsFrag); 311 } 312 } 313 314 // Completed the read of the full record. Acquire the reassembled 315 // messages. 316 if (reassembler != null) { 317 return reassembler.acquirePlaintext(); 318 } 319 320 if (debug != null && Debug.isOn("verbose")) { 321 Debug.log("The reassembler is not initialized yet."); 322 } 323 324 return null; 325 } 326 327 @Override 328 int bytesInCompletePacket(ByteBuffer packet) throws SSLException { 329 330 // DTLS length field is in bytes 11/12 331 if (packet.remaining() < headerSize) { 332 return -1; 333 } 334 335 // Last sanity check that it's not a wild record 336 int pos = packet.position(); 337 338 // Check the content type of the record. 339 byte contentType = packet.get(pos); 340 if (!Record.isValidContentType(contentType)) { 341 throw new SSLException( 342 "Unrecognized SSL message, plaintext connection?"); 343 } 344 345 // Check the protocol version of the record. 346 ProtocolVersion recordVersion = 347 ProtocolVersion.valueOf(packet.get(pos + 1), packet.get(pos + 2)); 348 checkRecordVersion(recordVersion, false); 349 350 // Get the fragment length of the record. 351 int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) + 352 (packet.get(pos + 12) & 0xFF) + headerSize; 353 if (fragLen > Record.maxFragmentSize) { 354 throw new SSLException( 355 "Record overflow, fragment length (" + fragLen + 356 ") MUST not exceed " + Record.maxFragmentSize); 357 } 358 359 return fragLen; 360 } 361 362 @Override 363 void checkRecordVersion(ProtocolVersion recordVersion, 364 boolean allowSSL20Hello) throws SSLException { 365 366 if (!recordVersion.maybeDTLSProtocol()) { 367 throw new SSLException( 368 "Unrecognized record version " + recordVersion + 369 " , plaintext connection?"); 370 } 371 } 372 373 private static HandshakeFragment parseHandshakeMessage( 374 byte contentType, byte majorVersion, byte minorVersion, 375 byte[] recordEnS, int recordEpoch, long recordSeq, 376 ByteBuffer plaintextFragment) { 377 378 int remaining = plaintextFragment.remaining(); 379 if (remaining < handshakeHeaderSize) { 380 if (debug != null && Debug.isOn("ssl")) { 381 Debug.log("Discard invalid record: " + 382 "too small record to hold a handshake fragment"); 383 } 384 385 // invalid, discard this record [section 4.1.2.7, RFC 6347] 386 return null; 387 } 388 389 byte handshakeType = plaintextFragment.get(); // pos: 0 390 int messageLength = 391 ((plaintextFragment.get() & 0xFF) << 16) | 392 ((plaintextFragment.get() & 0xFF) << 8) | 393 (plaintextFragment.get() & 0xFF); // pos: 1-3 394 int messageSeq = 395 ((plaintextFragment.get() & 0xFF) << 8) | 396 (plaintextFragment.get() & 0xFF); // pos: 4/5 397 int fragmentOffset = 398 ((plaintextFragment.get() & 0xFF) << 16) | 399 ((plaintextFragment.get() & 0xFF) << 8) | 400 (plaintextFragment.get() & 0xFF); // pos: 6-8 401 int fragmentLength = 402 ((plaintextFragment.get() & 0xFF) << 16) | 403 ((plaintextFragment.get() & 0xFF) << 8) | 404 (plaintextFragment.get() & 0xFF); // pos: 9-11 405 if ((remaining - handshakeHeaderSize) < fragmentLength) { 406 if (debug != null && Debug.isOn("ssl")) { 407 Debug.log("Discard invalid record: " + 408 "not a complete handshake fragment in the record"); 409 } 410 411 // invalid, discard this record [section 4.1.2.7, RFC 6347] 412 return null; 413 } 414 415 byte[] fragment = new byte[fragmentLength]; 416 plaintextFragment.get(fragment); 417 418 return new HandshakeFragment(fragment, contentType, 419 majorVersion, minorVersion, 420 recordEnS, recordEpoch, recordSeq, 421 handshakeType, messageLength, 422 messageSeq, fragmentOffset, fragmentLength); 423 } 424 425 // buffered record fragment 426 private static class RecordFragment implements Comparable<RecordFragment> { 427 boolean isCiphertext; 428 429 byte contentType; 430 byte majorVersion; 431 byte minorVersion; 432 int recordEpoch; 433 long recordSeq; 434 byte[] recordEnS; 435 byte[] fragment; 436 437 RecordFragment(ByteBuffer fragBuf, byte contentType, 438 byte majorVersion, byte minorVersion, byte[] recordEnS, 439 int recordEpoch, long recordSeq, boolean isCiphertext) { 440 this((byte[])null, contentType, majorVersion, minorVersion, 441 recordEnS, recordEpoch, recordSeq, isCiphertext); 442 443 this.fragment = new byte[fragBuf.remaining()]; 444 fragBuf.get(this.fragment); 445 } 446 447 RecordFragment(byte[] fragment, byte contentType, 448 byte majorVersion, byte minorVersion, byte[] recordEnS, 449 int recordEpoch, long recordSeq, boolean isCiphertext) { 450 this.isCiphertext = isCiphertext; 451 452 this.contentType = contentType; 453 this.majorVersion = majorVersion; 454 this.minorVersion = minorVersion; 455 this.recordEpoch = recordEpoch; 456 this.recordSeq = recordSeq; 457 this.recordEnS = recordEnS; 458 this.fragment = fragment; // The caller should have cloned 459 // the buffer if necessary. 460 } 461 462 @Override 463 public int compareTo(RecordFragment o) { 464 if (this.contentType == Record.ct_change_cipher_spec) { 465 if (o.contentType == Record.ct_change_cipher_spec) { 466 // Only one incoming ChangeCipherSpec message for an epoch. 467 // 468 // Ignore duplicated ChangeCipherSpec messages. 469 return Integer.compare(this.recordEpoch, o.recordEpoch); 470 } else if ((this.recordEpoch == o.recordEpoch) && 471 (o.contentType == Record.ct_handshake)) { 472 // ChangeCipherSpec is the latest message of an epoch. 473 return 1; 474 } 475 } else if (o.contentType == Record.ct_change_cipher_spec) { 476 if ((this.recordEpoch == o.recordEpoch) && 477 (this.contentType == Record.ct_handshake)) { 478 // ChangeCipherSpec is the latest message of an epoch. 479 return -1; 480 } else { 481 // different epoch or this is not a handshake message 482 return compareToSequence(o.recordEpoch, o.recordSeq); 483 } 484 } 485 486 return compareToSequence(o.recordEpoch, o.recordSeq); 487 } 488 489 int compareToSequence(int epoch, long seq) { 490 if (this.recordEpoch > epoch) { 491 return 1; 492 } else if (this.recordEpoch == epoch) { 493 return (int)(this.recordSeq - seq); 494 } else { 495 return -1; 496 } 497 } 498 } 499 500 // buffered handshake message 501 private static final class HandshakeFragment extends RecordFragment { 502 503 byte handshakeType; // handshake msg_type 504 int messageSeq; // message_seq 505 int messageLength; // Handshake body length 506 int fragmentOffset; // fragment_offset 507 int fragmentLength; // fragment_length 508 509 HandshakeFragment(byte[] fragment, byte contentType, 510 byte majorVersion, byte minorVersion, byte[] recordEnS, 511 int recordEpoch, long recordSeq, 512 byte handshakeType, int messageLength, 513 int messageSeq, int fragmentOffset, int fragmentLength) { 514 515 super(fragment, contentType, majorVersion, minorVersion, 516 recordEnS, recordEpoch , recordSeq, false); 517 518 this.handshakeType = handshakeType; 519 this.messageSeq = messageSeq; 520 this.messageLength = messageLength; 521 this.fragmentOffset = fragmentOffset; 522 this.fragmentLength = fragmentLength; 523 } 524 525 @Override 526 public int compareTo(RecordFragment o) { 527 if (o instanceof HandshakeFragment) { 528 HandshakeFragment other = (HandshakeFragment)o; 529 if (this.messageSeq != other.messageSeq) { 530 // keep the insertion order of handshake messages 531 return this.messageSeq - other.messageSeq; 532 } else if (this.fragmentOffset != other.fragmentOffset) { 533 // small fragment offset was transmitted first 534 return this.fragmentOffset - other.fragmentOffset; 535 } else if (this.fragmentLength == other.fragmentLength) { 536 // retransmissions, ignore duplicated messages. 537 return 0; 538 } 539 540 // Should be repacked for suitable fragment length. 541 // 542 // Note that the acquiring processes will reassemble the 543 // the fragments later. 544 return compareToSequence(o.recordEpoch, o.recordSeq); 545 } 546 547 return super.compareTo(o); 548 } 549 } 550 551 private static final class HoleDescriptor { 552 int offset; // fragment_offset 553 int limit; // fragment_offset + fragment_length 554 555 HoleDescriptor(int offset, int limit) { 556 this.offset = offset; 557 this.limit = limit; 558 } 559 } 560 561 private static final class HandshakeFlight implements Cloneable { 562 static final byte HF_UNKNOWN = HandshakeMessage.ht_not_applicable; 563 564 byte handshakeType; // handshake type 565 int flightEpoch; // the epoch of the first message 566 int minMessageSeq; // minimal message sequence 567 568 int maxMessageSeq; // maximum message sequence 569 int maxRecordEpoch; // maximum record sequence number 570 long maxRecordSeq; // maximum record sequence number 571 572 HashMap<Byte, List<HoleDescriptor>> holesMap; 573 574 HandshakeFlight() { 575 this.handshakeType = HF_UNKNOWN; 576 this.flightEpoch = 0; 577 this.minMessageSeq = 0; 578 579 this.maxMessageSeq = 0; 580 this.maxRecordEpoch = 0; 581 this.maxRecordSeq = -1; 582 583 this.holesMap = new HashMap<>(5); 584 } 585 586 boolean isRetransmitOf(HandshakeFlight hs) { 587 if (hs != null) { 588 return (this.handshakeType == hs.handshakeType) && 589 (this.minMessageSeq == hs.minMessageSeq); 590 } 591 592 return false; 593 } 594 595 @Override 596 public Object clone() { 597 HandshakeFlight hf = new HandshakeFlight(); 598 599 hf.handshakeType = this.handshakeType; 600 hf.flightEpoch = this.flightEpoch; 601 hf.minMessageSeq = this.minMessageSeq; 602 603 hf.maxMessageSeq = this.maxMessageSeq; 604 hf.maxRecordEpoch = this.maxRecordEpoch; 605 hf.maxRecordSeq = this.maxRecordSeq; 606 607 hf.holesMap = new HashMap<>(this.holesMap); 608 609 return hf; 610 } 611 } 612 613 final class DTLSReassembler { 614 // The handshake epoch. 615 final int handshakeEpoch; 616 617 // The buffered fragments. 618 TreeSet<RecordFragment> bufferedFragments = new TreeSet<>(); 619 620 // The handshake flight in progress. 621 HandshakeFlight handshakeFlight = new HandshakeFlight(); 622 623 // The preceding handshake flight. 624 HandshakeFlight precedingFlight = null; 625 626 // Epoch, sequence number and handshake message sequence of the 627 // next message acquisition of a flight. 628 int nextRecordEpoch; // next record epoch 629 long nextRecordSeq = 0; // next record sequence number 630 631 // Expect ChangeCipherSpec and Finished messages for the final flight. 632 boolean expectCCSFlight = false; 633 634 // Ready to process this flight if received all messages of the flight. 635 boolean flightIsReady = false; 636 boolean needToCheckFlight = false; 637 638 DTLSReassembler(int handshakeEpoch) { 639 this.handshakeEpoch = handshakeEpoch; 640 this.nextRecordEpoch = handshakeEpoch; 641 642 this.handshakeFlight.flightEpoch = handshakeEpoch; 643 } 644 645 void expectingFinishFlight() { 646 expectCCSFlight = true; 647 } 648 649 // Queue up a handshake message. 650 void queueUpHandshake(HandshakeFragment hsf) { 651 if (!isDesirable(hsf)) { 652 // No a dedired record, discard it. 653 return; 654 } 655 656 // Clean up the retransmission messages if necessary. 657 cleanUpRetransmit(hsf); 658 659 // Is it the first message of next flight? 660 // 661 // Note: the Finished message is handled in the final CCS flight. 662 boolean isMinimalFlightMessage = false; 663 if (handshakeFlight.minMessageSeq == hsf.messageSeq) { 664 isMinimalFlightMessage = true; 665 } else if ((precedingFlight != null) && 666 (precedingFlight.minMessageSeq == hsf.messageSeq)) { 667 isMinimalFlightMessage = true; 668 } 669 670 if (isMinimalFlightMessage && (hsf.fragmentOffset == 0) && 671 (hsf.handshakeType != HandshakeMessage.ht_finished)) { 672 673 // reset the handshake flight 674 handshakeFlight.handshakeType = hsf.handshakeType; 675 handshakeFlight.flightEpoch = hsf.recordEpoch; 676 handshakeFlight.minMessageSeq = hsf.messageSeq; 677 } 678 679 if (hsf.handshakeType == HandshakeMessage.ht_finished) { 680 handshakeFlight.maxMessageSeq = hsf.messageSeq; 681 handshakeFlight.maxRecordEpoch = hsf.recordEpoch; 682 handshakeFlight.maxRecordSeq = hsf.recordSeq; 683 } else { 684 if (handshakeFlight.maxMessageSeq < hsf.messageSeq) { 685 handshakeFlight.maxMessageSeq = hsf.messageSeq; 686 } 687 688 int n = (hsf.recordEpoch - handshakeFlight.maxRecordEpoch); 689 if (n > 0) { 690 handshakeFlight.maxRecordEpoch = hsf.recordEpoch; 691 handshakeFlight.maxRecordSeq = hsf.recordSeq; 692 } else if (n == 0) { 693 // the same epoch 694 if (handshakeFlight.maxRecordSeq < hsf.recordSeq) { 695 handshakeFlight.maxRecordSeq = hsf.recordSeq; 696 } 697 } // Otherwise, it is unlikely to happen. 698 } 699 700 boolean fragmented = false; 701 if ((hsf.fragmentOffset) != 0 || 702 (hsf.fragmentLength != hsf.messageLength)) { 703 704 fragmented = true; 705 } 706 707 List<HoleDescriptor> holes = 708 handshakeFlight.holesMap.get(hsf.handshakeType); 709 if (holes == null) { 710 if (!fragmented) { 711 holes = Collections.emptyList(); 712 } else { 713 holes = new LinkedList<HoleDescriptor>(); 714 holes.add(new HoleDescriptor(0, hsf.messageLength)); 715 } 716 handshakeFlight.holesMap.put(hsf.handshakeType, holes); 717 } else if (holes.isEmpty()) { 718 // Have got the full handshake message. This record may be 719 // a handshake message retransmission. Discard this record. 720 // 721 // It's OK to discard retransmission as the handshake hash 722 // is computed as if each handshake message had been sent 723 // as a single fragment. 724 if (debug != null && Debug.isOn("verbose")) { 725 Debug.log("Have got the full message, discard it."); 726 } 727 728 return; 729 } 730 731 if (fragmented) { 732 int fragmentLimit = hsf.fragmentOffset + hsf.fragmentLength; 733 for (int i = 0; i < holes.size(); i++) { 734 735 HoleDescriptor hole = holes.get(i); 736 if ((hole.limit <= hsf.fragmentOffset) || 737 (hole.offset >= fragmentLimit)) { 738 // Also discard overlapping handshake retransmissions. 739 continue; 740 } 741 742 // The ranges SHOULD NOT overlap. 743 if (((hole.offset > hsf.fragmentOffset) && 744 (hole.offset < fragmentLimit)) || 745 ((hole.limit > hsf.fragmentOffset) && 746 (hole.limit < fragmentLimit))) { 747 748 if (debug != null && Debug.isOn("ssl")) { 749 Debug.log("Discard invalid record: " + 750 "handshake fragment ranges are overlapping"); 751 } 752 753 // invalid, discard it [section 4.1.2.7, RFC 6347] 754 return; 755 } 756 757 // This record interacts with this hole, fill the hole. 758 holes.remove(i); 759 // i--; 760 761 if (hsf.fragmentOffset > hole.offset) { 762 holes.add(new HoleDescriptor( 763 hole.offset, hsf.fragmentOffset)); 764 // i++; 765 } 766 767 if (fragmentLimit < hole.limit) { 768 holes.add(new HoleDescriptor( 769 fragmentLimit, hole.limit)); 770 // i++; 771 } 772 773 // As no ranges overlap, no interact with other holes. 774 break; 775 } 776 } 777 778 // buffer this fragment 779 if (hsf.handshakeType == HandshakeMessage.ht_finished) { 780 // Need no status update. 781 bufferedFragments.add(hsf); 782 } else { 783 bufferFragment(hsf); 784 } 785 } 786 787 // Queue up a ChangeCipherSpec message 788 void queueUpChangeCipherSpec(RecordFragment rf) { 789 if (!isDesirable(rf)) { 790 // No a dedired record, discard it. 791 return; 792 } 793 794 // Clean up the retransmission messages if necessary. 795 cleanUpRetransmit(rf); 796 797 // Is it the first message of this flight? 798 // 799 // Note: the first message of the final flight is ChangeCipherSpec. 800 if (expectCCSFlight) { 801 handshakeFlight.handshakeType = HandshakeFlight.HF_UNKNOWN; 802 handshakeFlight.flightEpoch = rf.recordEpoch; 803 } 804 805 // The epoch should be the same as the first message of the flight. 806 if (handshakeFlight.maxRecordSeq < rf.recordSeq) { 807 handshakeFlight.maxRecordSeq = rf.recordSeq; 808 } 809 810 // buffer this fragment 811 bufferFragment(rf); 812 } 813 814 // Queue up a ciphertext message. 815 // 816 // Note: not yet be able to decrypt the message. 817 void queueUpFragment(RecordFragment rf) { 818 if (!isDesirable(rf)) { 819 // No a dedired record, discard it. 820 return; 821 } 822 823 // Clean up the retransmission messages if necessary. 824 cleanUpRetransmit(rf); 825 826 // buffer this fragment 827 bufferFragment(rf); 828 } 829 830 private void bufferFragment(RecordFragment rf) { 831 // append this fragment 832 bufferedFragments.add(rf); 833 834 if (flightIsReady) { 835 flightIsReady = false; 836 } 837 838 if (!needToCheckFlight) { 839 needToCheckFlight = true; 840 } 841 } 842 843 private void cleanUpRetransmit(RecordFragment rf) { 844 // Does the next flight start? 845 boolean isNewFlight = false; 846 if (precedingFlight != null) { 847 if (precedingFlight.flightEpoch < rf.recordEpoch) { 848 isNewFlight = true; 849 } else { 850 if (rf instanceof HandshakeFragment) { 851 HandshakeFragment hsf = (HandshakeFragment)rf; 852 if (precedingFlight.maxMessageSeq < hsf.messageSeq) { 853 isNewFlight = true; 854 } 855 } else if (rf.contentType != Record.ct_change_cipher_spec) { 856 // ciphertext 857 if (precedingFlight.maxRecordEpoch < rf.recordEpoch) { 858 isNewFlight = true; 859 } 860 } 861 } 862 } 863 864 if (!isNewFlight) { 865 // Need no cleanup. 866 return; 867 } 868 869 // clean up the buffer 870 for (Iterator<RecordFragment> it = bufferedFragments.iterator(); 871 it.hasNext();) { 872 873 RecordFragment frag = it.next(); 874 boolean isOld = false; 875 if (frag.recordEpoch < precedingFlight.maxRecordEpoch) { 876 isOld = true; 877 } else if (frag.recordEpoch == precedingFlight.maxRecordEpoch) { 878 if (frag.recordSeq <= precedingFlight.maxRecordSeq) { 879 isOld = true; 880 } 881 } 882 883 if (!isOld && (frag instanceof HandshakeFragment)) { 884 HandshakeFragment hsf = (HandshakeFragment)frag; 885 isOld = (hsf.messageSeq <= precedingFlight.maxMessageSeq); 886 } 887 888 if (isOld) { 889 it.remove(); 890 } else { 891 // Safe to break as items in the buffer are ordered. 892 break; 893 } 894 } 895 896 // discard retransmissions of the previous flight if any. 897 precedingFlight = null; 898 } 899 900 // Is a desired record? 901 // 902 // Check for retransmission and lost records. 903 private boolean isDesirable(RecordFragment rf) { 904 // 905 // Discard records old than the previous epoch. 906 // 907 int previousEpoch = nextRecordEpoch - 1; 908 if (rf.recordEpoch < previousEpoch) { 909 // Too old to use, discard this record. 910 if (debug != null && Debug.isOn("verbose")) { 911 Debug.log("Too old epoch to use this record, discard it."); 912 } 913 914 return false; 915 } 916 917 // 918 // Allow retransmission of last flight of the previous epoch 919 // 920 // For example, the last server delivered flight for session 921 // resuming abbreviated handshaking consist three messages: 922 // ServerHello 923 // [ChangeCipherSpec] 924 // Finished 925 // 926 // The epoch number is incremented and the sequence number is reset 927 // if the ChangeCipherSpec is sent. 928 if (rf.recordEpoch == previousEpoch) { 929 boolean isDesired = true; 930 if (precedingFlight == null) { 931 isDesired = false; 932 } else { 933 if (rf instanceof HandshakeFragment) { 934 HandshakeFragment hsf = (HandshakeFragment)rf; 935 if (precedingFlight.minMessageSeq > hsf.messageSeq) { 936 isDesired = false; 937 } 938 } else if (rf.contentType == Record.ct_change_cipher_spec) { 939 // ChangeCipherSpec 940 if (precedingFlight.flightEpoch != rf.recordEpoch) { 941 isDesired = false; 942 } 943 } else { // ciphertext 944 if ((rf.recordEpoch < precedingFlight.maxRecordEpoch) || 945 (rf.recordEpoch == precedingFlight.maxRecordEpoch && 946 rf.recordSeq <= precedingFlight.maxRecordSeq)) { 947 isDesired = false; 948 } 949 } 950 } 951 952 if (!isDesired) { 953 // Too old to use, discard this retransmitted record 954 if (debug != null && Debug.isOn("verbose")) { 955 Debug.log("Too old retransmission to use, discard it."); 956 } 957 958 return false; 959 } 960 } else if ((rf.recordEpoch == nextRecordEpoch) && 961 (nextRecordSeq > rf.recordSeq)) { 962 963 // Previously disordered record for the current epoch. 964 // 965 // Should has been retransmitted. Discard this record. 966 if (debug != null && Debug.isOn("verbose")) { 967 Debug.log("Lagging behind record (sequence), discard it."); 968 } 969 970 return false; 971 } 972 973 return true; 974 } 975 976 private boolean isEmpty() { 977 return (bufferedFragments.isEmpty() || 978 (!flightIsReady && !needToCheckFlight) || 979 (needToCheckFlight && !flightIsReady())); 980 } 981 982 Plaintext acquirePlaintext() { 983 if (bufferedFragments.isEmpty()) { 984 if (debug != null && Debug.isOn("verbose")) { 985 Debug.log("No received handshake messages"); 986 } 987 return null; 988 } 989 990 if (!flightIsReady && needToCheckFlight) { 991 // check the fligth status 992 flightIsReady = flightIsReady(); 993 994 // Reset if this flight is ready. 995 if (flightIsReady) { 996 // Retransmitted handshake messages are not needed for 997 // further handshaking processing. 998 if (handshakeFlight.isRetransmitOf(precedingFlight)) { 999 // cleanup 1000 bufferedFragments.clear(); 1001 1002 // Reset the next handshake flight. 1003 resetHandshakeFlight(precedingFlight); 1004 1005 if (debug != null && Debug.isOn("verbose")) { 1006 Debug.log("Received a retransmission flight."); 1007 } 1008 1009 return Plaintext.PLAINTEXT_NULL; 1010 } 1011 } 1012 1013 needToCheckFlight = false; 1014 } 1015 1016 if (!flightIsReady) { 1017 if (debug != null && Debug.isOn("verbose")) { 1018 Debug.log("The handshake flight is not ready to use: " + 1019 handshakeFlight.handshakeType); 1020 } 1021 return null; 1022 } 1023 1024 RecordFragment rFrag = bufferedFragments.first(); 1025 Plaintext plaintext; 1026 if (!rFrag.isCiphertext) { 1027 // handshake message, or ChangeCipherSpec message 1028 plaintext = acquireHandshakeMessage(); 1029 1030 // Reset the handshake flight. 1031 if (bufferedFragments.isEmpty()) { 1032 // Nedd not to backup the holes map. Clear up it at first. 1033 handshakeFlight.holesMap.clear(); // cleanup holes map 1034 1035 // Update the preceding flight. 1036 precedingFlight = (HandshakeFlight)handshakeFlight.clone(); 1037 1038 // Reset the next handshake flight. 1039 resetHandshakeFlight(precedingFlight); 1040 1041 if (expectCCSFlight && 1042 (precedingFlight.flightEpoch == 1043 HandshakeFlight.HF_UNKNOWN)) { 1044 expectCCSFlight = false; 1045 } 1046 } 1047 } else { 1048 // a Finished message or other ciphertexts 1049 plaintext = acquireCachedMessage(); 1050 } 1051 1052 return plaintext; 1053 } 1054 1055 // 1056 // Reset the handshake flight from a previous one. 1057 // 1058 private void resetHandshakeFlight(HandshakeFlight prev) { 1059 // Reset the next handshake flight. 1060 handshakeFlight.handshakeType = HandshakeFlight.HF_UNKNOWN; 1061 handshakeFlight.flightEpoch = prev.maxRecordEpoch; 1062 if (prev.flightEpoch != prev.maxRecordEpoch) { 1063 // a new epoch starts 1064 handshakeFlight.minMessageSeq = 0; 1065 } else { 1066 // stay at the same epoch 1067 // 1068 // The minimal message sequence number will get updated if 1069 // a flight retransmission happens. 1070 handshakeFlight.minMessageSeq = prev.maxMessageSeq + 1; 1071 } 1072 1073 // cleanup the maximum sequence number and epoch number. 1074 // 1075 // Note: actually, we need to do nothing because the reassembler 1076 // of handshake messages will reset them properly even for 1077 // retransmissions. 1078 // 1079 handshakeFlight.maxMessageSeq = 0; 1080 handshakeFlight.maxRecordEpoch = handshakeFlight.flightEpoch; 1081 1082 // Record sequence number cannot wrap even for retransmissions. 1083 handshakeFlight.maxRecordSeq = prev.maxRecordSeq + 1; 1084 1085 // cleanup holes map 1086 handshakeFlight.holesMap.clear(); 1087 1088 // Ready to accept new input record. 1089 flightIsReady = false; 1090 needToCheckFlight = false; 1091 } 1092 1093 private Plaintext acquireCachedMessage() { 1094 1095 RecordFragment rFrag = bufferedFragments.first(); 1096 if (readEpoch != rFrag.recordEpoch) { 1097 if (readEpoch > rFrag.recordEpoch) { 1098 // discard old records 1099 if (debug != null && Debug.isOn("verbose")) { 1100 Debug.log("Discard old buffered ciphertext fragments."); 1101 } 1102 bufferedFragments.remove(rFrag); // popup the fragment 1103 } 1104 1105 // reset the flight 1106 if (flightIsReady) { 1107 flightIsReady = false; 1108 } 1109 1110 if (debug != null && Debug.isOn("verbose")) { 1111 Debug.log("Not yet ready to decrypt the cached fragments."); 1112 } 1113 return null; 1114 } 1115 1116 bufferedFragments.remove(rFrag); // popup the fragment 1117 1118 ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment); 1119 ByteBuffer plaintextFragment = null; 1120 try { 1121 plaintextFragment = decrypt(readAuthenticator, readCipher, 1122 rFrag.contentType, fragment, rFrag.recordEnS); 1123 } catch (BadPaddingException bpe) { 1124 if (debug != null && Debug.isOn("verbose")) { 1125 Debug.log("Discard invalid record: " + bpe); 1126 } 1127 1128 // invalid, discard this record [section 4.1.2.7, RFC 6347] 1129 return null; 1130 } 1131 1132 // The ciphtext handshake message can only be Finished (the 1133 // end of this flight), ClinetHello or HelloRequest (the 1134 // beginning of the next flight) message. Need not to check 1135 // any ChangeCipherSpec message. 1136 if (rFrag.contentType == Record.ct_handshake) { 1137 while (plaintextFragment.remaining() > 0) { 1138 HandshakeFragment hsFrag = parseHandshakeMessage( 1139 rFrag.contentType, 1140 rFrag.majorVersion, rFrag.minorVersion, 1141 rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq, 1142 plaintextFragment); 1143 1144 if (hsFrag == null) { 1145 // invalid, discard this record 1146 if (debug != null && Debug.isOn("verbose")) { 1147 Debug.printHex( 1148 "Invalid handshake fragment, discard it", 1149 plaintextFragment); 1150 } 1151 return null; 1152 } 1153 1154 queueUpHandshake(hsFrag); 1155 // The flight ready status (flightIsReady) should have 1156 // been checked and updated for the Finished handshake 1157 // message before the decryption. Please don't update 1158 // flightIsReady for Finished messages. 1159 if (hsFrag.handshakeType != HandshakeMessage.ht_finished) { 1160 flightIsReady = false; 1161 needToCheckFlight = true; 1162 } 1163 } 1164 1165 return acquirePlaintext(); 1166 } else { 1167 return new Plaintext(rFrag.contentType, 1168 rFrag.majorVersion, rFrag.minorVersion, 1169 rFrag.recordEpoch, 1170 Authenticator.toLong(rFrag.recordEnS), 1171 plaintextFragment); 1172 } 1173 } 1174 1175 private Plaintext acquireHandshakeMessage() { 1176 1177 RecordFragment rFrag = bufferedFragments.first(); 1178 if (rFrag.contentType == Record.ct_change_cipher_spec) { 1179 this.nextRecordEpoch = rFrag.recordEpoch + 1; 1180 1181 // For retransmissions, the next record sequence number is a 1182 // positive value. Don't worry about it as the acquiring of 1183 // the immediately followed Finished handshake message will 1184 // reset the next record sequence number correctly. 1185 this.nextRecordSeq = 0; 1186 1187 // Popup the fragment. 1188 bufferedFragments.remove(rFrag); 1189 1190 // Reload if this message has been reserved for handshake hash. 1191 handshakeHash.reload(); 1192 1193 return new Plaintext(rFrag.contentType, 1194 rFrag.majorVersion, rFrag.minorVersion, 1195 rFrag.recordEpoch, 1196 Authenticator.toLong(rFrag.recordEnS), 1197 ByteBuffer.wrap(rFrag.fragment)); 1198 } else { // rFrag.contentType == Record.ct_handshake 1199 HandshakeFragment hsFrag = (HandshakeFragment)rFrag; 1200 if ((hsFrag.messageLength == hsFrag.fragmentLength) && 1201 (hsFrag.fragmentOffset == 0)) { // no fragmentation 1202 1203 bufferedFragments.remove(rFrag); // popup the fragment 1204 1205 // this.nextRecordEpoch = hsFrag.recordEpoch; 1206 this.nextRecordSeq = hsFrag.recordSeq + 1; 1207 1208 // Note: may try to avoid byte array copy in the future. 1209 byte[] recordFrag = new byte[hsFrag.messageLength + 4]; 1210 Plaintext plaintext = new Plaintext(hsFrag.contentType, 1211 hsFrag.majorVersion, hsFrag.minorVersion, 1212 hsFrag.recordEpoch, 1213 Authenticator.toLong(hsFrag.recordEnS), 1214 ByteBuffer.wrap(recordFrag)); 1215 1216 // fill the handshake fragment of the record 1217 recordFrag[0] = hsFrag.handshakeType; 1218 recordFrag[1] = 1219 (byte)((hsFrag.messageLength >>> 16) & 0xFF); 1220 recordFrag[2] = 1221 (byte)((hsFrag.messageLength >>> 8) & 0xFF); 1222 recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF); 1223 1224 System.arraycopy(hsFrag.fragment, 0, 1225 recordFrag, 4, hsFrag.fragmentLength); 1226 1227 // handshake hashing 1228 handshakeHashing(hsFrag, plaintext); 1229 1230 return plaintext; 1231 } else { // fragmented handshake message 1232 // the first record 1233 // 1234 // Note: may try to avoid byte array copy in the future. 1235 byte[] recordFrag = new byte[hsFrag.messageLength + 4]; 1236 Plaintext plaintext = new Plaintext(hsFrag.contentType, 1237 hsFrag.majorVersion, hsFrag.minorVersion, 1238 hsFrag.recordEpoch, 1239 Authenticator.toLong(hsFrag.recordEnS), 1240 ByteBuffer.wrap(recordFrag)); 1241 1242 // fill the handshake fragment of the record 1243 recordFrag[0] = hsFrag.handshakeType; 1244 recordFrag[1] = 1245 (byte)((hsFrag.messageLength >>> 16) & 0xFF); 1246 recordFrag[2] = 1247 (byte)((hsFrag.messageLength >>> 8) & 0xFF); 1248 recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF); 1249 1250 int msgSeq = hsFrag.messageSeq; 1251 long maxRecodeSN = hsFrag.recordSeq; 1252 HandshakeFragment hmFrag = hsFrag; 1253 do { 1254 System.arraycopy(hmFrag.fragment, 0, 1255 recordFrag, hmFrag.fragmentOffset + 4, 1256 hmFrag.fragmentLength); 1257 // popup the fragment 1258 bufferedFragments.remove(rFrag); 1259 1260 if (maxRecodeSN < hmFrag.recordSeq) { 1261 maxRecodeSN = hmFrag.recordSeq; 1262 } 1263 1264 // Note: may buffer retransmitted fragments in order to 1265 // speed up the reassembly in the future. 1266 1267 // read the next buffered record 1268 if (!bufferedFragments.isEmpty()) { 1269 rFrag = bufferedFragments.first(); 1270 if (rFrag.contentType != Record.ct_handshake) { 1271 break; 1272 } else { 1273 hmFrag = (HandshakeFragment)rFrag; 1274 } 1275 } 1276 } while (!bufferedFragments.isEmpty() && 1277 (msgSeq == hmFrag.messageSeq)); 1278 1279 // handshake hashing 1280 handshakeHashing(hsFrag, plaintext); 1281 1282 this.nextRecordSeq = maxRecodeSN + 1; 1283 1284 return plaintext; 1285 } 1286 } 1287 } 1288 1289 boolean flightIsReady() { 1290 1291 byte flightType = handshakeFlight.handshakeType; 1292 if (flightType == HandshakeFlight.HF_UNKNOWN) { 1293 // 1294 // the ChangeCipherSpec/Finished flight 1295 // 1296 if (expectCCSFlight) { 1297 // Have the ChangeCipherSpec/Finished flight been received? 1298 // 1299 // return hasFinisedMessage(bufferedFragments); 1300 boolean isReady = hasFinisedMessage(bufferedFragments); 1301 if (debug != null && Debug.isOn("verbose")) { 1302 Debug.log( 1303 "Has the final flight been received? " + isReady); 1304 } 1305 1306 return isReady; 1307 } 1308 1309 if (debug != null && Debug.isOn("verbose")) { 1310 Debug.log("No flight is received yet."); 1311 } 1312 1313 return false; 1314 } 1315 1316 if ((flightType == HandshakeMessage.ht_client_hello) || 1317 (flightType == HandshakeMessage.ht_hello_request) || 1318 (flightType == HandshakeMessage.ht_hello_verify_request)) { 1319 1320 // single handshake message flight 1321 boolean isReady = hasCompleted(flightType); 1322 if (debug != null && Debug.isOn("verbose")) { 1323 Debug.log("Is the handshake message completed? " + isReady); 1324 } 1325 1326 return isReady; 1327 } 1328 1329 // 1330 // the ServerHello flight 1331 // 1332 if (flightType == HandshakeMessage.ht_server_hello) { 1333 // Firstly, check the first flight handshake message. 1334 if (!hasCompleted(flightType)) { 1335 if (debug != null && Debug.isOn("verbose")) { 1336 Debug.log( 1337 "The ServerHello message is not completed yet."); 1338 } 1339 1340 return false; 1341 } 1342 1343 // 1344 // an abbreviated handshake 1345 // 1346 if (hasFinisedMessage(bufferedFragments)) { 1347 if (debug != null && Debug.isOn("verbose")) { 1348 Debug.log("It's an abbreviated handshake."); 1349 } 1350 1351 return true; 1352 } 1353 1354 // 1355 // a full handshake 1356 // 1357 List<HoleDescriptor> holes = handshakeFlight.holesMap.get( 1358 HandshakeMessage.ht_server_hello_done); 1359 if ((holes == null) || !holes.isEmpty()) { 1360 // Not yet got the final message of the flight. 1361 if (debug != null && Debug.isOn("verbose")) { 1362 Debug.log("Not yet got the ServerHelloDone message"); 1363 } 1364 1365 return false; 1366 } 1367 1368 // Have all handshake message been received? 1369 boolean isReady = hasCompleted(bufferedFragments, 1370 handshakeFlight.minMessageSeq, 1371 handshakeFlight.maxMessageSeq); 1372 if (debug != null && Debug.isOn("verbose")) { 1373 Debug.log("Is the ServerHello flight (message " + 1374 handshakeFlight.minMessageSeq + "-" + 1375 handshakeFlight.maxMessageSeq + 1376 ") completed? " + isReady); 1377 } 1378 1379 return isReady; 1380 } 1381 1382 // 1383 // the ClientKeyExchange flight 1384 // 1385 // Note: need to consider more messages in this flight if 1386 // ht_supplemental_data and ht_certificate_url are 1387 // suppported in the future. 1388 // 1389 if ((flightType == HandshakeMessage.ht_certificate) || 1390 (flightType == HandshakeMessage.ht_client_key_exchange)) { 1391 1392 // Firstly, check the first flight handshake message. 1393 if (!hasCompleted(flightType)) { 1394 if (debug != null && Debug.isOn("verbose")) { 1395 Debug.log( 1396 "The ClientKeyExchange or client Certificate " + 1397 "message is not completed yet."); 1398 } 1399 1400 return false; 1401 } 1402 1403 if (!hasFinisedMessage(bufferedFragments)) { 1404 // not yet have the ChangeCipherSpec/Finished messages 1405 if (debug != null && Debug.isOn("verbose")) { 1406 Debug.log( 1407 "Not yet have the ChangeCipherSpec and " + 1408 "Finished messages"); 1409 } 1410 1411 return false; 1412 } 1413 1414 // Have all handshake message been received? 1415 boolean isReady = hasCompleted(bufferedFragments, 1416 handshakeFlight.minMessageSeq, 1417 handshakeFlight.maxMessageSeq); 1418 if (debug != null && Debug.isOn("verbose")) { 1419 Debug.log("Is the ClientKeyExchange flight (message " + 1420 handshakeFlight.minMessageSeq + "-" + 1421 handshakeFlight.maxMessageSeq + 1422 ") completed? " + isReady); 1423 } 1424 1425 return isReady; 1426 } 1427 1428 // 1429 // Otherwise, need to receive more handshake messages. 1430 // 1431 if (debug != null && Debug.isOn("verbose")) { 1432 Debug.log("Need to receive more handshake messages"); 1433 } 1434 1435 return false; 1436 } 1437 1438 private boolean isSessionResuming( 1439 byte[] fragment, byte[] prevSid) throws SSLException { 1440 1441 // As the first fragment of ServerHello should be big enough 1442 // to hold the session_id field, need not to worry about the 1443 // fragmentation here. 1444 if ((fragment == null) || (fragment.length < 38)) { 1445 // 38: the minimal ServerHello body length 1446 throw new SSLException( 1447 "Invalid ServerHello message: no sufficient data"); 1448 } 1449 1450 int sidLen = fragment[34]; // 34: the length field 1451 if (sidLen > 32) { // opaque SessionID<0, 32> 1452 throw new SSLException( 1453 "Invalid ServerHello message: invalid session id"); 1454 } 1455 1456 if (fragment.length < 38 + sidLen) { 1457 throw new SSLException( 1458 "Invalid ServerHello message: no sufficient data"); 1459 } 1460 1461 if (sidLen != 0 && (prevSid.length == sidLen)) { 1462 // may be a session-resuming handshake 1463 for (int i = 0; i < sidLen; i++) { 1464 if (prevSid[i] != fragment[35 + i]) { 1465 // 35: the session identifier 1466 return false; 1467 } 1468 } 1469 1470 return true; 1471 } 1472 1473 return false; 1474 } 1475 1476 private byte[] getSessionID(byte[] fragment) { 1477 // The validity has been checked in the call to isSessionResuming(). 1478 int sidLen = fragment[34]; // 34: the sessionID length field 1479 1480 byte[] temporary = new byte[sidLen]; 1481 System.arraycopy(fragment, 35, temporary, 0, sidLen); 1482 1483 return temporary; 1484 } 1485 1486 // Looking for the ChangeCipherSpec and Finished messages. 1487 // 1488 // As the cached Finished message should be a ciphertext, we don't 1489 // exactly know a ciphertext is a Finished message or not. According 1490 // to the spec of TLS/DTLS handshaking, a Finished message is always 1491 // sent immediately after a ChangeCipherSpec message. The first 1492 // ciphertext handshake message should be the expected Finished message. 1493 private boolean hasFinisedMessage( 1494 Set<RecordFragment> fragments) { 1495 1496 boolean hasCCS = false; 1497 boolean hasFin = false; 1498 for (RecordFragment fragment : fragments) { 1499 if (fragment.contentType == Record.ct_change_cipher_spec) { 1500 if (hasFin) { 1501 return true; 1502 } 1503 hasCCS = true; 1504 } else if (fragment.contentType == Record.ct_handshake) { 1505 // Finished is the first expected message of a new epoch. 1506 if (fragment.isCiphertext) { 1507 if (hasCCS) { 1508 return true; 1509 } 1510 hasFin = true; 1511 } 1512 } 1513 } 1514 1515 return hasFin && hasCCS; 1516 } 1517 1518 private boolean hasCompleted(byte handshakeType) { 1519 List<HoleDescriptor> holes = 1520 handshakeFlight.holesMap.get(handshakeType); 1521 if (holes == null) { 1522 // not yet received this kind of handshake message 1523 return false; 1524 } 1525 1526 return holes.isEmpty(); // no fragment hole for complete message 1527 } 1528 1529 private boolean hasCompleted( 1530 Set<RecordFragment> fragments, 1531 int presentMsgSeq, int endMsgSeq) { 1532 1533 // The caller should have checked the completion of the first 1534 // present handshake message. Need not to check it again. 1535 for (RecordFragment rFrag : fragments) { 1536 if ((rFrag.contentType != Record.ct_handshake) || 1537 rFrag.isCiphertext) { 1538 break; 1539 } 1540 1541 HandshakeFragment hsFrag = (HandshakeFragment)rFrag; 1542 if (hsFrag.messageSeq == presentMsgSeq) { 1543 continue; 1544 } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) { 1545 // check the completion of the handshake message 1546 if (!hasCompleted(hsFrag.handshakeType)) { 1547 return false; 1548 } 1549 1550 presentMsgSeq = hsFrag.messageSeq; 1551 } else { 1552 // not yet got handshake message next to presentMsgSeq 1553 break; 1554 } 1555 } 1556 1557 return (presentMsgSeq >= endMsgSeq); 1558 // false: if not yet got all messages of the flight. 1559 } 1560 1561 private void handshakeHashing( 1562 HandshakeFragment hsFrag, Plaintext plaintext) { 1563 1564 byte hsType = hsFrag.handshakeType; 1565 if ((hsType == HandshakeMessage.ht_hello_request) || 1566 (hsType == HandshakeMessage.ht_hello_verify_request)) { 1567 1568 // omitted from handshake hash computation 1569 return; 1570 } 1571 1572 if ((hsFrag.messageSeq == 0) && 1573 (hsType == HandshakeMessage.ht_client_hello)) { 1574 1575 // omit initial ClientHello message 1576 // 1577 // 4: handshake header 1578 // 2: ClientHello.client_version 1579 // 32: ClientHello.random 1580 int sidLen = plaintext.fragment.get(38); 1581 1582 if (sidLen == 0) { // empty session_id, initial handshake 1583 return; 1584 } 1585 } 1586 1587 // calculate the DTLS header 1588 byte[] temporary = new byte[12]; // 12: handshake header size 1589 1590 // Handshake.msg_type 1591 temporary[0] = hsFrag.handshakeType; 1592 1593 // Handshake.length 1594 temporary[1] = (byte)((hsFrag.messageLength >> 16) & 0xFF); 1595 temporary[2] = (byte)((hsFrag.messageLength >> 8) & 0xFF); 1596 temporary[3] = (byte)(hsFrag.messageLength & 0xFF); 1597 1598 // Handshake.message_seq 1599 temporary[4] = (byte)((hsFrag.messageSeq >> 8) & 0xFF); 1600 temporary[5] = (byte)(hsFrag.messageSeq & 0xFF); 1601 1602 // Handshake.fragment_offset 1603 temporary[6] = 0; 1604 temporary[7] = 0; 1605 temporary[8] = 0; 1606 1607 // Handshake.fragment_length 1608 temporary[9] = temporary[1]; 1609 temporary[10] = temporary[2]; 1610 temporary[11] = temporary[3]; 1611 1612 plaintext.fragment.position(4); // ignore the TLS header 1613 if ((hsType != HandshakeMessage.ht_finished) && 1614 (hsType != HandshakeMessage.ht_certificate_verify)) { 1615 1616 if (handshakeHash == null) { 1617 // used for cache only 1618 handshakeHash = new HandshakeHash(false); 1619 } 1620 handshakeHash.update(temporary, 0, 12); 1621 handshakeHash.update(plaintext.fragment); 1622 } else { 1623 // Reserve until this handshake message has been processed. 1624 if (handshakeHash == null) { 1625 // used for cache only 1626 handshakeHash = new HandshakeHash(false); 1627 } 1628 handshakeHash.reserve(temporary, 0, 12); 1629 handshakeHash.reserve(plaintext.fragment); 1630 } 1631 plaintext.fragment.position(0); // restore the position 1632 } 1633 } 1634 } 1635