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