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 record", 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 Long.compare(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 return (hs != null) && 588 (this.handshakeType == hs.handshakeType) && 589 (this.minMessageSeq == hs.minMessageSeq); 590 } 591 592 @Override 593 public Object clone() { 594 HandshakeFlight hf = new HandshakeFlight(); 595 596 hf.handshakeType = this.handshakeType; 597 hf.flightEpoch = this.flightEpoch; 598 hf.minMessageSeq = this.minMessageSeq; 599 600 hf.maxMessageSeq = this.maxMessageSeq; 601 hf.maxRecordEpoch = this.maxRecordEpoch; 602 hf.maxRecordSeq = this.maxRecordSeq; 603 604 hf.holesMap = new HashMap<>(this.holesMap); 605 606 return hf; 607 } 608 } 609 610 final class DTLSReassembler { 611 // The handshake epoch. 612 final int handshakeEpoch; 613 614 // The buffered fragments. 615 TreeSet<RecordFragment> bufferedFragments = new TreeSet<>(); 616 617 // The handshake flight in progress. 618 HandshakeFlight handshakeFlight = new HandshakeFlight(); 619 620 // The preceding handshake flight. 621 HandshakeFlight precedingFlight = null; 622 623 // Epoch, sequence number and handshake message sequence of the 624 // next message acquisition of a flight. 625 int nextRecordEpoch; // next record epoch 626 long nextRecordSeq = 0; // next record sequence number 627 628 // Expect ChangeCipherSpec and Finished messages for the final flight. 629 boolean expectCCSFlight = false; 630 631 // Ready to process this flight if received all messages of the flight. 632 boolean flightIsReady = false; 633 boolean needToCheckFlight = false; 634 635 DTLSReassembler(int handshakeEpoch) { 636 this.handshakeEpoch = handshakeEpoch; 637 this.nextRecordEpoch = handshakeEpoch; 638 639 this.handshakeFlight.flightEpoch = handshakeEpoch; 640 } 641 642 void expectingFinishFlight() { 643 expectCCSFlight = true; 644 } 645 646 // Queue up a handshake message. 647 void queueUpHandshake(HandshakeFragment hsf) { 648 if (!isDesirable(hsf)) { 649 // Not a dedired record, discard it. 650 return; 651 } 652 653 // Clean up the retransmission messages if necessary. 654 cleanUpRetransmit(hsf); 655 656 // Is it the first message of next flight? 657 // 658 // Note: the Finished message is handled in the final CCS flight. 659 boolean isMinimalFlightMessage = false; 660 if (handshakeFlight.minMessageSeq == hsf.messageSeq) { 661 isMinimalFlightMessage = true; 662 } else if ((precedingFlight != null) && 663 (precedingFlight.minMessageSeq == hsf.messageSeq)) { 664 isMinimalFlightMessage = true; 665 } 666 667 if (isMinimalFlightMessage && (hsf.fragmentOffset == 0) && 668 (hsf.handshakeType != HandshakeMessage.ht_finished)) { 669 670 // reset the handshake flight 671 handshakeFlight.handshakeType = hsf.handshakeType; 672 handshakeFlight.flightEpoch = hsf.recordEpoch; 673 handshakeFlight.minMessageSeq = hsf.messageSeq; 674 } 675 676 if (hsf.handshakeType == HandshakeMessage.ht_finished) { 677 handshakeFlight.maxMessageSeq = hsf.messageSeq; 678 handshakeFlight.maxRecordEpoch = hsf.recordEpoch; 679 handshakeFlight.maxRecordSeq = hsf.recordSeq; 680 } else { 681 if (handshakeFlight.maxMessageSeq < hsf.messageSeq) { 682 handshakeFlight.maxMessageSeq = hsf.messageSeq; 683 } 684 685 int n = (hsf.recordEpoch - handshakeFlight.maxRecordEpoch); 686 if (n > 0) { 687 handshakeFlight.maxRecordEpoch = hsf.recordEpoch; 688 handshakeFlight.maxRecordSeq = hsf.recordSeq; 689 } else if (n == 0) { 690 // the same epoch 691 if (handshakeFlight.maxRecordSeq < hsf.recordSeq) { 692 handshakeFlight.maxRecordSeq = hsf.recordSeq; 693 } 694 } // Otherwise, it is unlikely to happen. 695 } 696 697 boolean fragmented = false; 698 if ((hsf.fragmentOffset) != 0 || 699 (hsf.fragmentLength != hsf.messageLength)) { 700 701 fragmented = true; 702 } 703 704 List<HoleDescriptor> holes = 705 handshakeFlight.holesMap.get(hsf.handshakeType); 706 if (holes == null) { 707 if (!fragmented) { 708 holes = Collections.emptyList(); 709 } else { 710 holes = new LinkedList<HoleDescriptor>(); 711 holes.add(new HoleDescriptor(0, hsf.messageLength)); 712 } 713 handshakeFlight.holesMap.put(hsf.handshakeType, holes); 714 } else if (holes.isEmpty()) { 715 // Have got the full handshake message. This record may be 716 // a handshake message retransmission. Discard this record. 717 // 718 // It's OK to discard retransmission as the handshake hash 719 // is computed as if each handshake message had been sent 720 // as a single fragment. 721 if (debug != null && Debug.isOn("verbose")) { 722 Debug.log("Have got the full message, discard it."); 723 } 724 725 return; 726 } 727 728 if (fragmented) { 729 int fragmentLimit = hsf.fragmentOffset + hsf.fragmentLength; 730 for (int i = 0; i < holes.size(); i++) { 731 732 HoleDescriptor hole = holes.get(i); 733 if ((hole.limit <= hsf.fragmentOffset) || 734 (hole.offset >= fragmentLimit)) { 735 // Also discard overlapping handshake retransmissions. 736 continue; 737 } 738 739 // The ranges SHOULD NOT overlap. 740 if (((hole.offset > hsf.fragmentOffset) && 741 (hole.offset < fragmentLimit)) || 742 ((hole.limit > hsf.fragmentOffset) && 743 (hole.limit < fragmentLimit))) { 744 745 if (debug != null && Debug.isOn("ssl")) { 746 Debug.log("Discard invalid record: " + 747 "handshake fragment ranges are overlapping"); 748 } 749 750 // invalid, discard it [section 4.1.2.7, RFC 6347] 751 return; 752 } 753 754 // This record interacts with this hole, fill the hole. 755 holes.remove(i); 756 // i--; 757 758 if (hsf.fragmentOffset > hole.offset) { 759 holes.add(new HoleDescriptor( 760 hole.offset, hsf.fragmentOffset)); 761 // i++; 762 } 763 764 if (fragmentLimit < hole.limit) { 765 holes.add(new HoleDescriptor( 766 fragmentLimit, hole.limit)); 767 // i++; 768 } 769 770 // As no ranges overlap, no interact with other holes. 771 break; 772 } 773 } 774 775 // buffer this fragment 776 if (hsf.handshakeType == HandshakeMessage.ht_finished) { 777 // Need no status update. 778 bufferedFragments.add(hsf); 779 } else { 780 bufferFragment(hsf); 781 } 782 } 783 784 // Queue up a ChangeCipherSpec message 785 void queueUpChangeCipherSpec(RecordFragment rf) { 786 if (!isDesirable(rf)) { 787 // Not a dedired record, discard it. 788 return; 789 } 790 791 // Clean up the retransmission messages if necessary. 792 cleanUpRetransmit(rf); 793 794 // Is it the first message of this flight? 795 // 796 // Note: the first message of the final flight is ChangeCipherSpec. 797 if (expectCCSFlight) { 798 handshakeFlight.handshakeType = HandshakeFlight.HF_UNKNOWN; 799 handshakeFlight.flightEpoch = rf.recordEpoch; 800 } 801 802 // The epoch should be the same as the first message of the flight. 803 if (handshakeFlight.maxRecordSeq < rf.recordSeq) { 804 handshakeFlight.maxRecordSeq = rf.recordSeq; 805 } 806 807 // buffer this fragment 808 bufferFragment(rf); 809 } 810 811 // Queue up a ciphertext message. 812 // 813 // Note: not yet be able to decrypt the message. 814 void queueUpFragment(RecordFragment rf) { 815 if (!isDesirable(rf)) { 816 // Not a dedired record, discard it. 817 return; 818 } 819 820 // Clean up the retransmission messages if necessary. 821 cleanUpRetransmit(rf); 822 823 // buffer this fragment 824 bufferFragment(rf); 825 } 826 827 private void bufferFragment(RecordFragment rf) { 828 // append this fragment 829 bufferedFragments.add(rf); 830 831 if (flightIsReady) { 832 flightIsReady = false; 833 } 834 835 if (!needToCheckFlight) { 836 needToCheckFlight = true; 837 } 838 } 839 840 private void cleanUpRetransmit(RecordFragment rf) { 841 // Does the next flight start? 842 boolean isNewFlight = false; 843 if (precedingFlight != null) { 844 if (precedingFlight.flightEpoch < rf.recordEpoch) { 845 isNewFlight = true; 846 } else { 847 if (rf instanceof HandshakeFragment) { 848 HandshakeFragment hsf = (HandshakeFragment)rf; 849 if (precedingFlight.maxMessageSeq < hsf.messageSeq) { 850 isNewFlight = true; 851 } 852 } else if (rf.contentType != Record.ct_change_cipher_spec) { 853 // ciphertext 854 if (precedingFlight.maxRecordEpoch < rf.recordEpoch) { 855 isNewFlight = true; 856 } 857 } 858 } 859 } 860 861 if (!isNewFlight) { 862 // Need no cleanup. 863 return; 864 } 865 866 // clean up the buffer 867 for (Iterator<RecordFragment> it = bufferedFragments.iterator(); 868 it.hasNext();) { 869 870 RecordFragment frag = it.next(); 871 boolean isOld = false; 872 if (frag.recordEpoch < precedingFlight.maxRecordEpoch) { 873 isOld = true; 874 } else if (frag.recordEpoch == precedingFlight.maxRecordEpoch) { 875 if (frag.recordSeq <= precedingFlight.maxRecordSeq) { 876 isOld = true; 877 } 878 } 879 880 if (!isOld && (frag instanceof HandshakeFragment)) { 881 HandshakeFragment hsf = (HandshakeFragment)frag; 882 isOld = (hsf.messageSeq <= precedingFlight.maxMessageSeq); 883 } 884 885 if (isOld) { 886 it.remove(); 887 } else { 888 // Safe to break as items in the buffer are ordered. 889 break; 890 } 891 } 892 893 // discard retransmissions of the previous flight if any. 894 precedingFlight = null; 895 } 896 897 // Is a desired record? 898 // 899 // Check for retransmission and lost records. 900 private boolean isDesirable(RecordFragment rf) { 901 // 902 // Discard records old than the previous epoch. 903 // 904 int previousEpoch = nextRecordEpoch - 1; 905 if (rf.recordEpoch < previousEpoch) { 906 // Too old to use, discard this record. 907 if (debug != null && Debug.isOn("verbose")) { 908 Debug.log("Too old epoch to use this record, discard it."); 909 } 910 911 return false; 912 } 913 914 // 915 // Allow retransmission of last flight of the previous epoch 916 // 917 // For example, the last server delivered flight for session 918 // resuming abbreviated handshaking consist three messages: 919 // ServerHello 920 // [ChangeCipherSpec] 921 // Finished 922 // 923 // The epoch number is incremented and the sequence number is reset 924 // if the ChangeCipherSpec is sent. 925 if (rf.recordEpoch == previousEpoch) { 926 boolean isDesired = true; 927 if (precedingFlight == null) { 928 isDesired = false; 929 } else { 930 if (rf instanceof HandshakeFragment) { 931 HandshakeFragment hsf = (HandshakeFragment)rf; 932 if (precedingFlight.minMessageSeq > hsf.messageSeq) { 933 isDesired = false; 934 } 935 } else if (rf.contentType == Record.ct_change_cipher_spec) { 936 // ChangeCipherSpec 937 if (precedingFlight.flightEpoch != rf.recordEpoch) { 938 isDesired = false; 939 } 940 } else { // ciphertext 941 if ((rf.recordEpoch < precedingFlight.maxRecordEpoch) || 942 (rf.recordEpoch == precedingFlight.maxRecordEpoch && 943 rf.recordSeq <= precedingFlight.maxRecordSeq)) { 944 isDesired = false; 945 } 946 } 947 } 948 949 if (!isDesired) { 950 // Too old to use, discard this retransmitted record 951 if (debug != null && Debug.isOn("verbose")) { 952 Debug.log("Too old retransmission to use, discard it."); 953 } 954 955 return false; 956 } 957 } else if ((rf.recordEpoch == nextRecordEpoch) && 958 (nextRecordSeq > rf.recordSeq)) { 959 960 // Previously disordered record for the current epoch. 961 // 962 // Should has been retransmitted. Discard this record. 963 if (debug != null && Debug.isOn("verbose")) { 964 Debug.log("Lagging behind record (sequence), discard it."); 965 } 966 967 return false; 968 } 969 970 return true; 971 } 972 973 private boolean isEmpty() { 974 return (bufferedFragments.isEmpty() || 975 (!flightIsReady && !needToCheckFlight) || 976 (needToCheckFlight && !flightIsReady())); 977 } 978 979 Plaintext acquirePlaintext() { 980 if (bufferedFragments.isEmpty()) { 981 if (debug != null && Debug.isOn("verbose")) { 982 Debug.log("No received handshake messages"); 983 } 984 return null; 985 } 986 987 if (!flightIsReady && needToCheckFlight) { 988 // check the fligth status 989 flightIsReady = flightIsReady(); 990 991 // Reset if this flight is ready. 992 if (flightIsReady) { 993 // Retransmitted handshake messages are not needed for 994 // further handshaking processing. 995 if (handshakeFlight.isRetransmitOf(precedingFlight)) { 996 // cleanup 997 bufferedFragments.clear(); 998 999 // Reset the next handshake flight. 1000 resetHandshakeFlight(precedingFlight); 1001 1002 if (debug != null && Debug.isOn("verbose")) { 1003 Debug.log("Received a retransmission flight."); 1004 } 1005 1006 return Plaintext.PLAINTEXT_NULL; 1007 } 1008 } 1009 1010 needToCheckFlight = false; 1011 } 1012 1013 if (!flightIsReady) { 1014 if (debug != null && Debug.isOn("verbose")) { 1015 Debug.log("The handshake flight is not ready to use: " + 1016 handshakeFlight.handshakeType); 1017 } 1018 return null; 1019 } 1020 1021 RecordFragment rFrag = bufferedFragments.first(); 1022 Plaintext plaintext; 1023 if (!rFrag.isCiphertext) { 1024 // handshake message, or ChangeCipherSpec message 1025 plaintext = acquireHandshakeMessage(); 1026 1027 // Reset the handshake flight. 1028 if (bufferedFragments.isEmpty()) { 1029 // Need not to backup the holes map. Clear up it at first. 1030 handshakeFlight.holesMap.clear(); // cleanup holes map 1031 1032 // Update the preceding flight. 1033 precedingFlight = (HandshakeFlight)handshakeFlight.clone(); 1034 1035 // Reset the next handshake flight. 1036 resetHandshakeFlight(precedingFlight); 1037 1038 if (expectCCSFlight && 1039 (precedingFlight.flightEpoch == 1040 HandshakeFlight.HF_UNKNOWN)) { 1041 expectCCSFlight = false; 1042 } 1043 } 1044 } else { 1045 // a Finished message or other ciphertexts 1046 plaintext = acquireCachedMessage(); 1047 } 1048 1049 return plaintext; 1050 } 1051 1052 // 1053 // Reset the handshake flight from a previous one. 1054 // 1055 private void resetHandshakeFlight(HandshakeFlight prev) { 1056 // Reset the next handshake flight. 1057 handshakeFlight.handshakeType = HandshakeFlight.HF_UNKNOWN; 1058 handshakeFlight.flightEpoch = prev.maxRecordEpoch; 1059 if (prev.flightEpoch != prev.maxRecordEpoch) { 1060 // a new epoch starts 1061 handshakeFlight.minMessageSeq = 0; 1062 } else { 1063 // stay at the same epoch 1064 // 1065 // The minimal message sequence number will get updated if 1066 // a flight retransmission happens. 1067 handshakeFlight.minMessageSeq = prev.maxMessageSeq + 1; 1068 } 1069 1070 // cleanup the maximum sequence number and epoch number. 1071 // 1072 // Note: actually, we need to do nothing because the reassembler 1073 // of handshake messages will reset them properly even for 1074 // retransmissions. 1075 // 1076 handshakeFlight.maxMessageSeq = 0; 1077 handshakeFlight.maxRecordEpoch = handshakeFlight.flightEpoch; 1078 1079 // Record sequence number cannot wrap even for retransmissions. 1080 handshakeFlight.maxRecordSeq = prev.maxRecordSeq + 1; 1081 1082 // cleanup holes map 1083 handshakeFlight.holesMap.clear(); 1084 1085 // Ready to accept new input record. 1086 flightIsReady = false; 1087 needToCheckFlight = false; 1088 } 1089 1090 private Plaintext acquireCachedMessage() { 1091 1092 RecordFragment rFrag = bufferedFragments.first(); 1093 if (readEpoch != rFrag.recordEpoch) { 1094 if (readEpoch > rFrag.recordEpoch) { 1095 // discard old records 1096 if (debug != null && Debug.isOn("verbose")) { 1097 Debug.log("Discard old buffered ciphertext fragments."); 1098 } 1099 bufferedFragments.remove(rFrag); // popup the fragment 1100 } 1101 1102 // reset the flight 1103 if (flightIsReady) { 1104 flightIsReady = false; 1105 } 1106 1107 if (debug != null && Debug.isOn("verbose")) { 1108 Debug.log("Not yet ready to decrypt the cached fragments."); 1109 } 1110 return null; 1111 } 1112 1113 bufferedFragments.remove(rFrag); // popup the fragment 1114 1115 ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment); 1116 ByteBuffer plaintextFragment = null; 1117 try { 1118 plaintextFragment = decrypt(readAuthenticator, readCipher, 1119 rFrag.contentType, fragment, rFrag.recordEnS); 1120 } catch (BadPaddingException bpe) { 1121 if (debug != null && Debug.isOn("verbose")) { 1122 Debug.log("Discard invalid record: " + bpe); 1123 } 1124 1125 // invalid, discard this record [section 4.1.2.7, RFC 6347] 1126 return null; 1127 } 1128 1129 // The ciphtext handshake message can only be Finished (the 1130 // end of this flight), ClinetHello or HelloRequest (the 1131 // beginning of the next flight) message. Need not to check 1132 // any ChangeCipherSpec message. 1133 if (rFrag.contentType == Record.ct_handshake) { 1134 while (plaintextFragment.remaining() > 0) { 1135 HandshakeFragment hsFrag = parseHandshakeMessage( 1136 rFrag.contentType, 1137 rFrag.majorVersion, rFrag.minorVersion, 1138 rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq, 1139 plaintextFragment); 1140 1141 if (hsFrag == null) { 1142 // invalid, discard this record 1143 if (debug != null && Debug.isOn("verbose")) { 1144 Debug.printHex( 1145 "Invalid handshake fragment, discard it", 1146 plaintextFragment); 1147 } 1148 return null; 1149 } 1150 1151 queueUpHandshake(hsFrag); 1152 // The flight ready status (flightIsReady) should have 1153 // been checked and updated for the Finished handshake 1154 // message before the decryption. Please don't update 1155 // flightIsReady for Finished messages. 1156 if (hsFrag.handshakeType != HandshakeMessage.ht_finished) { 1157 flightIsReady = false; 1158 needToCheckFlight = true; 1159 } 1160 } 1161 1162 return acquirePlaintext(); 1163 } else { 1164 return new Plaintext(rFrag.contentType, 1165 rFrag.majorVersion, rFrag.minorVersion, 1166 rFrag.recordEpoch, 1167 Authenticator.toLong(rFrag.recordEnS), 1168 plaintextFragment); 1169 } 1170 } 1171 1172 private Plaintext acquireHandshakeMessage() { 1173 1174 RecordFragment rFrag = bufferedFragments.first(); 1175 if (rFrag.contentType == Record.ct_change_cipher_spec) { 1176 this.nextRecordEpoch = rFrag.recordEpoch + 1; 1177 1178 // For retransmissions, the next record sequence number is a 1179 // positive value. Don't worry about it as the acquiring of 1180 // the immediately followed Finished handshake message will 1181 // reset the next record sequence number correctly. 1182 this.nextRecordSeq = 0; 1183 1184 // Popup the fragment. 1185 bufferedFragments.remove(rFrag); 1186 1187 // Reload if this message has been reserved for handshake hash. 1188 handshakeHash.reload(); 1189 1190 return new Plaintext(rFrag.contentType, 1191 rFrag.majorVersion, rFrag.minorVersion, 1192 rFrag.recordEpoch, 1193 Authenticator.toLong(rFrag.recordEnS), 1194 ByteBuffer.wrap(rFrag.fragment)); 1195 } else { // rFrag.contentType == Record.ct_handshake 1196 HandshakeFragment hsFrag = (HandshakeFragment)rFrag; 1197 if ((hsFrag.messageLength == hsFrag.fragmentLength) && 1198 (hsFrag.fragmentOffset == 0)) { // no fragmentation 1199 1200 bufferedFragments.remove(rFrag); // popup the fragment 1201 1202 // this.nextRecordEpoch = hsFrag.recordEpoch; 1203 this.nextRecordSeq = hsFrag.recordSeq + 1; 1204 1205 // Note: may try to avoid byte array copy in the future. 1206 byte[] recordFrag = new byte[hsFrag.messageLength + 4]; 1207 Plaintext plaintext = new Plaintext(hsFrag.contentType, 1208 hsFrag.majorVersion, hsFrag.minorVersion, 1209 hsFrag.recordEpoch, 1210 Authenticator.toLong(hsFrag.recordEnS), 1211 ByteBuffer.wrap(recordFrag)); 1212 1213 // fill the handshake fragment of the record 1214 recordFrag[0] = hsFrag.handshakeType; 1215 recordFrag[1] = 1216 (byte)((hsFrag.messageLength >>> 16) & 0xFF); 1217 recordFrag[2] = 1218 (byte)((hsFrag.messageLength >>> 8) & 0xFF); 1219 recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF); 1220 1221 System.arraycopy(hsFrag.fragment, 0, 1222 recordFrag, 4, hsFrag.fragmentLength); 1223 1224 // handshake hashing 1225 handshakeHashing(hsFrag, plaintext); 1226 1227 return plaintext; 1228 } else { // fragmented handshake message 1229 // the first record 1230 // 1231 // Note: may try to avoid byte array copy in the future. 1232 byte[] recordFrag = new byte[hsFrag.messageLength + 4]; 1233 Plaintext plaintext = new Plaintext(hsFrag.contentType, 1234 hsFrag.majorVersion, hsFrag.minorVersion, 1235 hsFrag.recordEpoch, 1236 Authenticator.toLong(hsFrag.recordEnS), 1237 ByteBuffer.wrap(recordFrag)); 1238 1239 // fill the handshake fragment of the record 1240 recordFrag[0] = hsFrag.handshakeType; 1241 recordFrag[1] = 1242 (byte)((hsFrag.messageLength >>> 16) & 0xFF); 1243 recordFrag[2] = 1244 (byte)((hsFrag.messageLength >>> 8) & 0xFF); 1245 recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF); 1246 1247 int msgSeq = hsFrag.messageSeq; 1248 long maxRecodeSN = hsFrag.recordSeq; 1249 HandshakeFragment hmFrag = hsFrag; 1250 do { 1251 System.arraycopy(hmFrag.fragment, 0, 1252 recordFrag, hmFrag.fragmentOffset + 4, 1253 hmFrag.fragmentLength); 1254 // popup the fragment 1255 bufferedFragments.remove(rFrag); 1256 1257 if (maxRecodeSN < hmFrag.recordSeq) { 1258 maxRecodeSN = hmFrag.recordSeq; 1259 } 1260 1261 // Note: may buffer retransmitted fragments in order to 1262 // speed up the reassembly in the future. 1263 1264 // read the next buffered record 1265 if (!bufferedFragments.isEmpty()) { 1266 rFrag = bufferedFragments.first(); 1267 if (rFrag.contentType != Record.ct_handshake) { 1268 break; 1269 } else { 1270 hmFrag = (HandshakeFragment)rFrag; 1271 } 1272 } 1273 } while (!bufferedFragments.isEmpty() && 1274 (msgSeq == hmFrag.messageSeq)); 1275 1276 // handshake hashing 1277 handshakeHashing(hsFrag, plaintext); 1278 1279 this.nextRecordSeq = maxRecodeSN + 1; 1280 1281 return plaintext; 1282 } 1283 } 1284 } 1285 1286 boolean flightIsReady() { 1287 1288 byte flightType = handshakeFlight.handshakeType; 1289 if (flightType == HandshakeFlight.HF_UNKNOWN) { 1290 // 1291 // the ChangeCipherSpec/Finished flight 1292 // 1293 if (expectCCSFlight) { 1294 // Have the ChangeCipherSpec/Finished flight been received? 1295 boolean isReady = hasFinishedMessage(bufferedFragments); 1296 if (debug != null && Debug.isOn("verbose")) { 1297 Debug.log( 1298 "Has the final flight been received? " + isReady); 1299 } 1300 1301 return isReady; 1302 } 1303 1304 if (debug != null && Debug.isOn("verbose")) { 1305 Debug.log("No flight is received yet."); 1306 } 1307 1308 return false; 1309 } 1310 1311 if ((flightType == HandshakeMessage.ht_client_hello) || 1312 (flightType == HandshakeMessage.ht_hello_request) || 1313 (flightType == HandshakeMessage.ht_hello_verify_request)) { 1314 1315 // single handshake message flight 1316 boolean isReady = hasCompleted(flightType); 1317 if (debug != null && Debug.isOn("verbose")) { 1318 Debug.log("Is the handshake message completed? " + isReady); 1319 } 1320 1321 return isReady; 1322 } 1323 1324 // 1325 // the ServerHello flight 1326 // 1327 if (flightType == HandshakeMessage.ht_server_hello) { 1328 // Firstly, check the first flight handshake message. 1329 if (!hasCompleted(flightType)) { 1330 if (debug != null && Debug.isOn("verbose")) { 1331 Debug.log( 1332 "The ServerHello message is not completed yet."); 1333 } 1334 1335 return false; 1336 } 1337 1338 // 1339 // an abbreviated handshake 1340 // 1341 if (hasFinishedMessage(bufferedFragments)) { 1342 if (debug != null && Debug.isOn("verbose")) { 1343 Debug.log("It's an abbreviated handshake."); 1344 } 1345 1346 return true; 1347 } 1348 1349 // 1350 // a full handshake 1351 // 1352 List<HoleDescriptor> holes = handshakeFlight.holesMap.get( 1353 HandshakeMessage.ht_server_hello_done); 1354 if ((holes == null) || !holes.isEmpty()) { 1355 // Not yet got the final message of the flight. 1356 if (debug != null && Debug.isOn("verbose")) { 1357 Debug.log("Not yet got the ServerHelloDone message"); 1358 } 1359 1360 return false; 1361 } 1362 1363 // Have all handshake message been received? 1364 boolean isReady = hasCompleted(bufferedFragments, 1365 handshakeFlight.minMessageSeq, 1366 handshakeFlight.maxMessageSeq); 1367 if (debug != null && Debug.isOn("verbose")) { 1368 Debug.log("Is the ServerHello flight (message " + 1369 handshakeFlight.minMessageSeq + "-" + 1370 handshakeFlight.maxMessageSeq + 1371 ") completed? " + isReady); 1372 } 1373 1374 return isReady; 1375 } 1376 1377 // 1378 // the ClientKeyExchange flight 1379 // 1380 // Note: need to consider more messages in this flight if 1381 // ht_supplemental_data and ht_certificate_url are 1382 // suppported in the future. 1383 // 1384 if ((flightType == HandshakeMessage.ht_certificate) || 1385 (flightType == HandshakeMessage.ht_client_key_exchange)) { 1386 1387 // Firstly, check the first flight handshake message. 1388 if (!hasCompleted(flightType)) { 1389 if (debug != null && Debug.isOn("verbose")) { 1390 Debug.log( 1391 "The ClientKeyExchange or client Certificate " + 1392 "message is not completed yet."); 1393 } 1394 1395 return false; 1396 } 1397 1398 if (!hasFinishedMessage(bufferedFragments)) { 1399 // not yet have the ChangeCipherSpec/Finished messages 1400 if (debug != null && Debug.isOn("verbose")) { 1401 Debug.log( 1402 "Not yet have the ChangeCipherSpec and " + 1403 "Finished messages"); 1404 } 1405 1406 return false; 1407 } 1408 1409 // Have all handshake message been received? 1410 boolean isReady = hasCompleted(bufferedFragments, 1411 handshakeFlight.minMessageSeq, 1412 handshakeFlight.maxMessageSeq); 1413 if (debug != null && Debug.isOn("verbose")) { 1414 Debug.log("Is the ClientKeyExchange flight (message " + 1415 handshakeFlight.minMessageSeq + "-" + 1416 handshakeFlight.maxMessageSeq + 1417 ") completed? " + isReady); 1418 } 1419 1420 return isReady; 1421 } 1422 1423 // 1424 // Otherwise, need to receive more handshake messages. 1425 // 1426 if (debug != null && Debug.isOn("verbose")) { 1427 Debug.log("Need to receive more handshake messages"); 1428 } 1429 1430 return false; 1431 } 1432 1433 private boolean isSessionResuming( 1434 byte[] fragment, byte[] prevSid) throws SSLException { 1435 1436 // As the first fragment of ServerHello should be big enough 1437 // to hold the session_id field, need not to worry about the 1438 // fragmentation here. 1439 if ((fragment == null) || (fragment.length < 38)) { 1440 // 38: the minimal ServerHello body length 1441 throw new SSLException( 1442 "Invalid ServerHello message: no sufficient data"); 1443 } 1444 1445 // SessionId.MAX_LENGTH is 32. 1446 int sidLen = fragment[34]; // 34: the length field 1447 if (sidLen > 32) { // opaque SessionID<0, 32> 1448 throw new SSLException( 1449 "Invalid ServerHello message: invalid session id"); 1450 } 1451 1452 if (fragment.length < 38 + sidLen) { 1453 throw new SSLException( 1454 "Invalid ServerHello message: no sufficient data"); 1455 } 1456 1457 if (sidLen != 0 && (prevSid.length == sidLen)) { 1458 // may be a session-resuming handshake 1459 for (int i = 0; i < sidLen; i++) { 1460 if (prevSid[i] != fragment[35 + i]) { 1461 // 35: the session identifier 1462 return false; 1463 } 1464 } 1465 1466 return true; 1467 } 1468 1469 return false; 1470 } 1471 1472 private byte[] getSessionID(byte[] fragment) { 1473 // The validity has been checked in the call to isSessionResuming(). 1474 int sidLen = fragment[34]; // 34: the sessionID length field 1475 1476 byte[] temporary = new byte[sidLen]; 1477 System.arraycopy(fragment, 35, temporary, 0, sidLen); 1478 1479 return temporary; 1480 } 1481 1482 // Looking for the ChangeCipherSpec and Finished messages. 1483 // 1484 // As the cached Finished message should be a ciphertext, we don't 1485 // exactly know a ciphertext is a Finished message or not. According 1486 // to the spec of TLS/DTLS handshaking, a Finished message is always 1487 // sent immediately after a ChangeCipherSpec message. The first 1488 // ciphertext handshake message should be the expected Finished message. 1489 private boolean hasFinishedMessage( 1490 Set<RecordFragment> fragments) { 1491 1492 boolean hasCCS = false; 1493 boolean hasFin = false; 1494 for (RecordFragment fragment : fragments) { 1495 if (fragment.contentType == Record.ct_change_cipher_spec) { 1496 if (hasFin) { 1497 return true; 1498 } 1499 hasCCS = true; 1500 } else if (fragment.contentType == Record.ct_handshake) { 1501 // Finished is the first expected message of a new epoch. 1502 if (fragment.isCiphertext) { 1503 if (hasCCS) { 1504 return true; 1505 } 1506 hasFin = true; 1507 } 1508 } 1509 } 1510 1511 return hasFin && hasCCS; 1512 } 1513 1514 private boolean hasCompleted(byte handshakeType) { 1515 List<HoleDescriptor> holes = 1516 handshakeFlight.holesMap.get(handshakeType); 1517 if (holes == null) { 1518 // not yet received this kind of handshake message 1519 return false; 1520 } 1521 1522 return holes.isEmpty(); // no fragment hole for complete message 1523 } 1524 1525 private boolean hasCompleted( 1526 Set<RecordFragment> fragments, 1527 int presentMsgSeq, int endMsgSeq) { 1528 1529 // The caller should have checked the completion of the first 1530 // present handshake message. Need not to check it again. 1531 for (RecordFragment rFrag : fragments) { 1532 if ((rFrag.contentType != Record.ct_handshake) || 1533 rFrag.isCiphertext) { 1534 break; 1535 } 1536 1537 HandshakeFragment hsFrag = (HandshakeFragment)rFrag; 1538 if (hsFrag.messageSeq == presentMsgSeq) { 1539 continue; 1540 } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) { 1541 // check the completion of the handshake message 1542 if (!hasCompleted(hsFrag.handshakeType)) { 1543 return false; 1544 } 1545 1546 presentMsgSeq = hsFrag.messageSeq; 1547 } else { 1548 // not yet got handshake message next to presentMsgSeq 1549 break; 1550 } 1551 } 1552 1553 return (presentMsgSeq >= endMsgSeq); 1554 // false: if not yet got all messages of the flight. 1555 } 1556 1557 private void handshakeHashing( 1558 HandshakeFragment hsFrag, Plaintext plaintext) { 1559 1560 byte hsType = hsFrag.handshakeType; 1561 if ((hsType == HandshakeMessage.ht_hello_request) || 1562 (hsType == HandshakeMessage.ht_hello_verify_request)) { 1563 1564 // omitted from handshake hash computation 1565 return; 1566 } 1567 1568 if ((hsFrag.messageSeq == 0) && 1569 (hsType == HandshakeMessage.ht_client_hello)) { 1570 1571 // omit initial ClientHello message 1572 // 1573 // 4: handshake header 1574 // 2: ClientHello.client_version 1575 // 32: ClientHello.random 1576 int sidLen = plaintext.fragment.get(38); 1577 1578 if (sidLen == 0) { // empty session_id, initial handshake 1579 return; 1580 } 1581 } 1582 1583 // calculate the DTLS header 1584 byte[] temporary = new byte[12]; // 12: handshake header size 1585 1586 // Handshake.msg_type 1587 temporary[0] = hsFrag.handshakeType; 1588 1589 // Handshake.length 1590 temporary[1] = (byte)((hsFrag.messageLength >> 16) & 0xFF); 1591 temporary[2] = (byte)((hsFrag.messageLength >> 8) & 0xFF); 1592 temporary[3] = (byte)(hsFrag.messageLength & 0xFF); 1593 1594 // Handshake.message_seq 1595 temporary[4] = (byte)((hsFrag.messageSeq >> 8) & 0xFF); 1596 temporary[5] = (byte)(hsFrag.messageSeq & 0xFF); 1597 1598 // Handshake.fragment_offset 1599 temporary[6] = 0; 1600 temporary[7] = 0; 1601 temporary[8] = 0; 1602 1603 // Handshake.fragment_length 1604 temporary[9] = temporary[1]; 1605 temporary[10] = temporary[2]; 1606 temporary[11] = temporary[3]; 1607 1608 plaintext.fragment.position(4); // ignore the TLS header 1609 if ((hsType != HandshakeMessage.ht_finished) && 1610 (hsType != HandshakeMessage.ht_certificate_verify)) { 1611 1612 if (handshakeHash == null) { 1613 // used for cache only 1614 handshakeHash = new HandshakeHash(false); 1615 } 1616 handshakeHash.update(temporary, 0, 12); 1617 handshakeHash.update(plaintext.fragment); 1618 } else { 1619 // Reserve until this handshake message has been processed. 1620 if (handshakeHash == null) { 1621 // used for cache only 1622 handshakeHash = new HandshakeHash(false); 1623 } 1624 handshakeHash.reserve(temporary, 0, 12); 1625 handshakeHash.reserve(plaintext.fragment); 1626 } 1627 plaintext.fragment.position(0); // restore the position 1628 } 1629 } 1630 } 1631