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