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