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