src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java

Print this page
8167680 DTLS implementation bugs
   1 /*
   2  * Copyright (c) 2015, 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


  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     // Cache the session identifier for the detection of session-resuming
  46     // handshake.
  47     byte[]              prevSessionID = new byte[0];
  48 
  49     int                 readEpoch;
  50 
  51     int                 prevReadEpoch;
  52     Authenticator       prevReadAuthenticator;
  53     CipherBox           prevReadCipher;
  54 
  55     DTLSInputRecord() {
  56         this.readEpoch = 0;
  57         this.readAuthenticator = new MAC(true);
  58 
  59         this.prevReadEpoch = 0;
  60         this.prevReadCipher = CipherBox.NULL;
  61         this.prevReadAuthenticator = new MAC(true);
  62     }
  63 
  64     @Override
  65     void changeReadCiphers(Authenticator readAuthenticator,
  66             CipherBox readCipher) {
  67 
  68         prevReadCipher.dispose();


  97         }
  98 
  99         if (packetSize > 0) {
 100             return readCipher.estimateFragmentSize(
 101                     packetSize, macLen, headerSize);
 102         } else {
 103             return Record.maxDataSize;
 104         }
 105     }
 106 
 107     @Override
 108     void expectingFinishFlight() {
 109         if (reassembler != null) {
 110             reassembler.expectingFinishFlight();
 111         }
 112     }
 113 
 114     @Override
 115     Plaintext acquirePlaintext() {
 116         if (reassembler != null) {
 117             Plaintext plaintext = reassembler.acquirePlaintext();
 118             if (reassembler.finished()) {
 119                 // discard all buffered unused message.
 120                 reassembler = null;
 121             }
 122 
 123             return plaintext;
 124         }
 125 
 126         return null;
 127     }
 128 
 129     @Override
 130     Plaintext decode(ByteBuffer packet) {
 131 
 132         if (isClosed) {
 133             return null;
 134         }
 135 
 136         if (debug != null && Debug.isOn("packet")) {
 137              Debug.printHex(
 138                     "[Raw read]: length = " + packet.remaining(), packet);
 139         }
 140 
 141         // The caller should have validated the record.
 142         int srcPos = packet.position();
 143         int srcLim = packet.limit();
 144 
 145         byte contentType = packet.get();                   // pos: 0
 146         byte majorVersion = packet.get();                  // pos: 1
 147         byte minorVersion = packet.get();                  // pos: 2
 148         byte[] recordEnS = new byte[8];                    // epoch + seqence
 149         packet.get(recordEnS);
 150         int recordEpoch = ((recordEnS[0] & 0xFF) << 8) |
 151                            (recordEnS[1] & 0xFF);          // pos: 3, 4
 152         long recordSeq  = Authenticator.toLong(recordEnS);






 153         int contentLen = ((packet.get() & 0xFF) << 8) |
 154                           (packet.get() & 0xFF);            // pos: 11, 12
 155 
 156         if (debug != null && Debug.isOn("record")) {
 157              System.out.println(Thread.currentThread().getName() +
 158                     ", READ: " +
 159                     ProtocolVersion.valueOf(majorVersion, minorVersion) +
 160                     " " + Record.contentName(contentType) + ", length = " +
 161                     contentLen);
 162         }
 163 
 164         int recLim = srcPos + DTLSRecord.headerSize + contentLen;
 165         if (this.readEpoch > recordEpoch) {
 166             // Discard old records delivered before this epoch.
 167 

 168             // Reset the position of the packet buffer.
 169             packet.position(recLim);



 170             return null;
 171         }
 172 

 173         if (this.readEpoch < recordEpoch) {
 174             if (contentType != Record.ct_handshake) {
 175                 // just discard it if not a handshake message





 176                 packet.position(recLim);
 177                 return null;


 178             }
 179 
 180             // Not ready to decrypt this record, may be encrypted Finished
 181             // message, need to buffer it.
 182             if (reassembler == null) {
 183                reassembler = new DTLSReassembler();
 184             }
 185 


 186             byte[] fragment = new byte[contentLen];
 187             packet.get(fragment);              // copy the fragment
 188             RecordFragment buffered = new RecordFragment(fragment, contentType,
 189                     majorVersion, minorVersion,
 190                     recordEnS, recordEpoch, recordSeq, true);
 191 
 192             reassembler.queueUpFragment(buffered);
 193 
 194             // consume the full record in the packet buffer.
 195             packet.position(recLim);
 196 
 197             Plaintext plaintext = reassembler.acquirePlaintext();
 198             if (reassembler.finished()) {
 199                 // discard all buffered unused message.
 200                 reassembler = null;
 201             }
 202 
 203             return plaintext;










 204         }
 205 
 206         if (this.readEpoch == recordEpoch) {
 207             // decrypt the fragment
 208             packet.limit(recLim);
 209             packet.position(srcPos + DTLSRecord.headerSize);
 210 
 211             ByteBuffer plaintextFragment;
 212             try {
 213                 plaintextFragment = decrypt(readAuthenticator,
 214                         readCipher, contentType, packet, recordEnS);
 215             } catch (BadPaddingException bpe) {
 216                 if (debug != null && Debug.isOn("ssl")) {
 217                     System.out.println(Thread.currentThread().getName() +
 218                             " discard invalid record: " + bpe);
 219                 }
 220 
 221                 // invalid, discard this record [section 4.1.2.7, RFC 6347]
 222                 return null;
 223             } finally {
 224                 // comsume a complete record
 225                 packet.limit(srcLim);
 226                 packet.position(recLim);
 227             }
 228 
 229             if (contentType != Record.ct_change_cipher_spec &&
 230                 contentType != Record.ct_handshake) {   // app data or alert
 231                                                         // no retransmission










 232                return new Plaintext(contentType, majorVersion, minorVersion,
 233                         recordEpoch, recordSeq, plaintextFragment);

 234             }
 235 
 236             if (contentType == Record.ct_change_cipher_spec) {
 237                 if (reassembler == null) {

 238                     // handshake has not started, should be an
 239                     // old handshake message, discard it.






 240                     return null;
 241                 }
 242 
 243                 reassembler.queueUpFragment(



 244                         new RecordFragment(plaintextFragment, contentType,
 245                                 majorVersion, minorVersion,
 246                                 recordEnS, recordEpoch, recordSeq, false));
 247             } else {    // handshake record
 248                 // One record may contain 1+ more handshake messages.
 249                 while (plaintextFragment.remaining() > 0) {
 250 
 251                     HandshakeFragment hsFrag = parseHandshakeMessage(
 252                         contentType, majorVersion, minorVersion,
 253                         recordEnS, recordEpoch, recordSeq, plaintextFragment);
 254 
 255                     if (hsFrag == null) {
 256                         // invalid, discard this record




 257                         return null;
 258                     }
 259 
 260                     if ((reassembler == null) &&
 261                             isKickstart(hsFrag.handshakeType)) {
 262                        reassembler = new DTLSReassembler();





 263                     }
 264 
 265                     if (reassembler != null) {





 266                         reassembler.queueUpHandshake(hsFrag);
 267                     }   // else, just ignore the message.
 268                 }
 269             }
 270 
 271             // Completed the read of the full record. Acquire the reassembled
 272             // messages.
 273             if (reassembler != null) {
 274                 Plaintext plaintext = reassembler.acquirePlaintext();
 275                 if (reassembler.finished()) {
 276                     // discard all buffered unused message.
 277                     reassembler = null;
 278                 }
 279 
 280                 return plaintext;

 281             }
 282         }
 283 
 284         return null;    // make the complier happy
 285     }
 286 
 287     @Override
 288     int bytesInCompletePacket(ByteBuffer packet) throws SSLException {
 289 
 290         // DTLS length field is in bytes 11/12
 291         if (packet.remaining() < headerSize) {
 292             return -1;
 293         }
 294 
 295         // Last sanity check that it's not a wild record
 296         int pos = packet.position();
 297 
 298         // Check the content type of the record.
 299         byte contentType = packet.get(pos);
 300         if (!Record.isValidContentType(contentType)) {
 301             throw new SSLException(
 302                     "Unrecognized SSL message, plaintext connection?");
 303         }
 304 


 313         if (fragLen > Record.maxFragmentSize) {
 314             throw new SSLException(
 315                     "Record overflow, fragment length (" + fragLen +
 316                     ") MUST not exceed " + Record.maxFragmentSize);
 317         }
 318 
 319         return fragLen;
 320     }
 321 
 322     @Override
 323     void checkRecordVersion(ProtocolVersion recordVersion,
 324             boolean allowSSL20Hello) throws SSLException {
 325 
 326         if (!recordVersion.maybeDTLSProtocol()) {
 327             throw new SSLException(
 328                     "Unrecognized record version " + recordVersion +
 329                     " , plaintext connection?");
 330         }
 331     }
 332 
 333     private static boolean isKickstart(byte handshakeType) {
 334         return (handshakeType == HandshakeMessage.ht_client_hello) ||
 335                (handshakeType == HandshakeMessage.ht_hello_request) ||
 336                (handshakeType == HandshakeMessage.ht_hello_verify_request);
 337     }
 338 
 339     private static HandshakeFragment parseHandshakeMessage(
 340             byte contentType, byte majorVersion, byte minorVersion,
 341             byte[] recordEnS, int recordEpoch, long recordSeq,
 342             ByteBuffer plaintextFragment) {
 343 
 344         int remaining = plaintextFragment.remaining();
 345         if (remaining < handshakeHeaderSize) {
 346             if (debug != null && Debug.isOn("ssl")) {
 347                 System.out.println(
 348                         Thread.currentThread().getName() +
 349                         " discard invalid record: " +
 350                         "too small record to hold a handshake fragment");
 351             }
 352 
 353             // invalid, discard this record [section 4.1.2.7, RFC 6347]
 354             return null;
 355         }
 356 
 357         byte handshakeType = plaintextFragment.get();       // pos: 0
 358         int messageLength =
 359                 ((plaintextFragment.get() & 0xFF) << 16) |
 360                 ((plaintextFragment.get() & 0xFF) << 8) |
 361                  (plaintextFragment.get() & 0xFF);          // pos: 1-3
 362         int messageSeq =
 363                 ((plaintextFragment.get() & 0xFF) << 8) |
 364                  (plaintextFragment.get() & 0xFF);          // pos: 4/5
 365         int fragmentOffset =
 366                 ((plaintextFragment.get() & 0xFF) << 16) |
 367                 ((plaintextFragment.get() & 0xFF) << 8) |
 368                  (plaintextFragment.get() & 0xFF);          // pos: 6-8
 369         int fragmentLength =
 370                 ((plaintextFragment.get() & 0xFF) << 16) |
 371                 ((plaintextFragment.get() & 0xFF) << 8) |
 372                  (plaintextFragment.get() & 0xFF);          // pos: 9-11
 373         if ((remaining - handshakeHeaderSize) < fragmentLength) {
 374             if (debug != null && Debug.isOn("ssl")) {
 375                 System.out.println(
 376                         Thread.currentThread().getName() +
 377                         " discard invalid record: " +
 378                         "not a complete handshake fragment in the record");
 379             }
 380 
 381             // invalid, discard this record [section 4.1.2.7, RFC 6347]
 382             return null;
 383         }
 384 
 385         byte[] fragment = new byte[fragmentLength];
 386         plaintextFragment.get(fragment);
 387 
 388         return new HandshakeFragment(fragment, contentType,
 389                 majorVersion, minorVersion,
 390                 recordEnS, recordEpoch, recordSeq,
 391                 handshakeType, messageLength,
 392                 messageSeq, fragmentOffset, fragmentLength);
 393     }
 394 
 395     // buffered record fragment
 396     private static class RecordFragment implements Comparable<RecordFragment> {
 397         boolean         isCiphertext;


 414             fragBuf.get(this.fragment);
 415         }
 416 
 417         RecordFragment(byte[] fragment, byte contentType,
 418                 byte majorVersion, byte minorVersion, byte[] recordEnS,
 419                 int recordEpoch, long recordSeq, boolean isCiphertext) {
 420             this.isCiphertext = isCiphertext;
 421 
 422             this.contentType = contentType;
 423             this.majorVersion = majorVersion;
 424             this.minorVersion = minorVersion;
 425             this.recordEpoch = recordEpoch;
 426             this.recordSeq = recordSeq;
 427             this.recordEnS = recordEnS;
 428             this.fragment = fragment;       // The caller should have cloned
 429                                             // the buffer if necessary.
 430         }
 431 
 432         @Override
 433         public int compareTo(RecordFragment o) {
 434             return Long.compareUnsigned(this.recordSeq, o.recordSeq);









 435         }








 436     }

 437 














 438     // buffered handshake message
 439     private static final class HandshakeFragment extends RecordFragment {
 440 
 441         byte            handshakeType;     // handshake msg_type
 442         int             messageSeq;        // message_seq
 443         int             messageLength;     // Handshake body length
 444         int             fragmentOffset;    // fragment_offset
 445         int             fragmentLength;    // fragment_length
 446 
 447         HandshakeFragment(byte[] fragment, byte contentType,
 448                 byte majorVersion, byte minorVersion, byte[] recordEnS,
 449                 int recordEpoch, long recordSeq,
 450                 byte handshakeType, int messageLength,
 451                 int messageSeq, int fragmentOffset, int fragmentLength) {
 452 
 453             super(fragment, contentType, majorVersion, minorVersion,
 454                     recordEnS, recordEpoch , recordSeq, false);
 455 
 456             this.handshakeType = handshakeType;
 457             this.messageSeq = messageSeq;
 458             this.messageLength = messageLength;
 459             this.fragmentOffset = fragmentOffset;
 460             this.fragmentLength = fragmentLength;
 461         }
 462 
 463         @Override
 464         public int compareTo(RecordFragment o) {
 465             if (o instanceof HandshakeFragment) {
 466                 HandshakeFragment other = (HandshakeFragment)o;
 467                 if (this.messageSeq != other.messageSeq) {
 468                     // keep the insertion order for the same message
 469                     return this.messageSeq - other.messageSeq;






 470                 }






 471             }
 472 
 473             return Long.compareUnsigned(this.recordSeq, o.recordSeq);
 474         }
 475     }
 476 
 477     private static final class HoleDescriptor {
 478         int offset;             // fragment_offset
 479         int limit;              // fragment_offset + fragment_length
 480 
 481         HoleDescriptor(int offset, int limit) {
 482             this.offset = offset;
 483             this.limit = limit;
 484         }
 485     }
 486 

















































 487     final class DTLSReassembler {




 488         TreeSet<RecordFragment> bufferedFragments = new TreeSet<>();
 489 
 490         HashMap<Byte, List<HoleDescriptor>> holesMap = new HashMap<>(5);

 491 
 492         // Epoch, sequence number and handshake message sequence of the
 493         // beginning message of a flight.
 494         byte        flightType = (byte)0xFF;
 495 
 496         int         flightTopEpoch = 0;
 497         long        flightTopRecordSeq = -1;
 498         int         flightTopMessageSeq = 0;
 499 
 500         // Epoch, sequence number and handshake message sequence of the
 501         // next message acquisition of a flight.
 502         int         nextRecordEpoch = 0;    // next record epoch
 503         long        nextRecordSeq = 0;      // next record sequence number
 504         int         nextMessageSeq = 0;     // next handshake message number
 505 
 506         // Expect ChangeCipherSpec and Finished messages for the final flight.
 507         boolean     expectCCSFlight = false;
 508 
 509         // Ready to process this flight if received all messages of the flight.
 510         boolean     flightIsReady = false;
 511         boolean     needToCheckFlight = false;
 512 
 513         // Is it a session-resuming abbreviated handshake.?
 514         boolean     isAbbreviatedHandshake = false;

 515 
 516         // The handshke fragment with the biggest record sequence number
 517         // in a flight, not counting the Finished message.
 518         HandshakeFragment lastHandshakeFragment = null;
 519 
 520         // Is handshake (intput) finished?
 521         boolean handshakeFinished = false;
 522 
 523         DTLSReassembler() {
 524             // blank
 525         }
 526 
 527         boolean finished() {
 528             return handshakeFinished;
 529         }
 530 
 531         void expectingFinishFlight() {
 532             expectCCSFlight = true;
 533         }
 534 

 535         void queueUpHandshake(HandshakeFragment hsf) {
 536 
 537             if ((nextRecordEpoch > hsf.recordEpoch) ||
 538                     (nextRecordSeq > hsf.recordSeq) ||
 539                     (nextMessageSeq > hsf.messageSeq)) {
 540                 // too old, discard this record
 541                 return;
 542             }
 543 



 544             // Is it the first message of next flight?
 545             if ((flightTopMessageSeq == hsf.messageSeq) &&
 546                     (hsf.fragmentOffset == 0) && (flightTopRecordSeq == -1)) {







 547 
 548                 flightType = hsf.handshakeType;
 549                 flightTopEpoch = hsf.recordEpoch;
 550                 flightTopRecordSeq = hsf.recordSeq;
 551 
 552                 if (hsf.handshakeType == HandshakeMessage.ht_server_hello) {
 553                     // Is it a session-resuming handshake?
 554                     try {
 555                         isAbbreviatedHandshake =
 556                                 isSessionResuming(hsf.fragment, prevSessionID);
 557                     } catch (SSLException ssle) {
 558                         if (debug != null && Debug.isOn("ssl")) {
 559                             System.out.println(
 560                                     Thread.currentThread().getName() +
 561                                     " discard invalid record: " + ssle);
 562                         }
 563 
 564                         // invalid, discard it [section 4.1.2.7, RFC 6347]
 565                         return;





 566                     }
 567 
 568                     if (!isAbbreviatedHandshake) {
 569                         prevSessionID = getSessionID(hsf.fragment);






 570                     }

 571                 }
 572             }
 573 
 574             boolean fragmented = false;
 575             if ((hsf.fragmentOffset) != 0 ||
 576                 (hsf.fragmentLength != hsf.messageLength)) {
 577 
 578                 fragmented = true;
 579             }
 580 
 581             List<HoleDescriptor> holes = holesMap.get(hsf.handshakeType);

 582             if (holes == null) {
 583                 if (!fragmented) {
 584                     holes = Collections.emptyList();
 585                 } else {
 586                     holes = new LinkedList<HoleDescriptor>();
 587                     holes.add(new HoleDescriptor(0, hsf.messageLength));
 588                 }
 589                 holesMap.put(hsf.handshakeType, holes);
 590             } else if (holes.isEmpty()) {
 591                 // Have got the full handshake message.  This record may be
 592                 // a handshake message retransmission.  Discard this record.
 593                 //
 594                 // It's OK to discard retransmission as the handshake hash
 595                 // is computed as if each handshake message had been sent
 596                 // as a single fragment.
 597                 //
 598                 // Note that ClientHello messages are delivered twice in
 599                 // DTLS handshaking.
 600                 if ((hsf.handshakeType != HandshakeMessage.ht_client_hello &&
 601                      hsf.handshakeType != ht_hello_verify_request) ||
 602                         (nextMessageSeq != hsf.messageSeq)) {
 603                     return;
 604                 }
 605 
 606                 if (fragmented) {
 607                     holes = new LinkedList<HoleDescriptor>();
 608                     holes.add(new HoleDescriptor(0, hsf.messageLength));
 609                 }
 610                 holesMap.put(hsf.handshakeType, holes);
 611             }
 612 
 613             if (fragmented) {
 614                 int fragmentLimit = hsf.fragmentOffset + hsf.fragmentLength;
 615                 for (int i = 0; i < holes.size(); i++) {
 616 
 617                     HoleDescriptor hole = holes.get(i);
 618                     if ((hole.limit <= hsf.fragmentOffset) ||
 619                         (hole.offset >= fragmentLimit)) {
 620                         // Also discard overlapping handshake retransmissions.
 621                         continue;
 622                     }
 623 
 624                     // The ranges SHOULD NOT overlap.
 625                     if (((hole.offset > hsf.fragmentOffset) &&
 626                          (hole.offset < fragmentLimit)) ||
 627                         ((hole.limit > hsf.fragmentOffset) &&
 628                          (hole.limit < fragmentLimit))) {
 629 
 630                         if (debug != null && Debug.isOn("ssl")) {
 631                             System.out.println(
 632                                 Thread.currentThread().getName() +
 633                                 " discard invalid record: " +
 634                                 "handshake fragment ranges are overlapping");
 635                         }
 636 
 637                         // invalid, discard it [section 4.1.2.7, RFC 6347]
 638                         return;
 639                     }
 640 
 641                     // This record interacts with this hole, fill the hole.
 642                     holes.remove(i);
 643                     // i--;
 644 
 645                     if (hsf.fragmentOffset > hole.offset) {
 646                         holes.add(new HoleDescriptor(
 647                                 hole.offset, hsf.fragmentOffset));
 648                         // i++;
 649                     }
 650 
 651                     if (fragmentLimit < hole.limit) {
 652                         holes.add(new HoleDescriptor(
 653                                 fragmentLimit, hole.limit));
 654                         // i++;
 655                     }
 656 
 657                     // As no ranges overlap, no interact with other holes.
 658                     break;
 659                 }
 660             }
 661 
 662             // append this fragment


 663             bufferedFragments.add(hsf);




 664 
 665             if ((lastHandshakeFragment == null) ||
 666                 (lastHandshakeFragment.compareTo(hsf) < 0)) {




 667 
 668                 lastHandshakeFragment = hsf;








 669             }
 670 
 671             if (flightIsReady) {
 672                 flightIsReady = false;

 673             }
 674             needToCheckFlight = true;


 675         }
 676 
 677         // queue up change_cipher_spec or encrypted message


 678         void queueUpFragment(RecordFragment rf) {
 679             if ((nextRecordEpoch > rf.recordEpoch) ||
 680                     (nextRecordSeq > rf.recordSeq)) {
 681                 // too old, discard this record
 682                 return;
 683             }
 684 
 685             // Is it the first message of next flight?
 686             if (expectCCSFlight &&
 687                     (rf.contentType == Record.ct_change_cipher_spec)) {
 688 
 689                 flightType = (byte)0xFE;
 690                 flightTopEpoch = rf.recordEpoch;
 691                 flightTopRecordSeq = rf.recordSeq;
 692             }
 693 

 694             // append this fragment
 695             bufferedFragments.add(rf);
 696 
 697             if (flightIsReady) {
 698                 flightIsReady = false;
 699             }


 700             needToCheckFlight = true;
 701         }

 702 
 703         boolean isEmpty() {





































































































































 704             return (bufferedFragments.isEmpty() ||
 705                     (!flightIsReady && !needToCheckFlight) ||
 706                     (needToCheckFlight && !flightIsReady()));
 707         }
 708 
 709         Plaintext acquirePlaintext() {
 710             if (bufferedFragments.isEmpty()) {
 711                 // reset the flight
 712                 if (flightIsReady) {
 713                     flightIsReady = false;
 714                     needToCheckFlight = false;
 715                 }
 716 
 717                 return null;
 718             }
 719 
 720             if (!flightIsReady && needToCheckFlight) {
 721                 // check the fligth status
 722                 flightIsReady = flightIsReady();
 723 
 724                 // set for next flight
 725                 if (flightIsReady) {
 726                     flightTopMessageSeq = lastHandshakeFragment.messageSeq + 1;
 727                     flightTopRecordSeq = -1;









 728                 }
 729 




 730                 needToCheckFlight = false;
 731             }
 732 
 733             if (!flightIsReady) {




 734                 return null;
 735             }
 736 
 737             RecordFragment rFrag = bufferedFragments.first();

 738             if (!rFrag.isCiphertext) {
 739                 // handshake message, or ChangeCipherSpec message
 740                 return acquireHandshakeMessage();


















 741             } else {
 742                 // a Finished message or other ciphertexts
 743                 return acquireCachedMessage();
 744             }


 745         }
 746 






































 747         private Plaintext acquireCachedMessage() {
 748 
 749             RecordFragment rFrag = bufferedFragments.first();
 750             if (readEpoch != rFrag.recordEpoch) {
 751                 if (readEpoch > rFrag.recordEpoch) {
 752                     // discard old records



 753                     bufferedFragments.remove(rFrag);    // popup the fragment
 754                 }
 755 
 756                 // reset the flight
 757                 if (flightIsReady) {
 758                     flightIsReady = false;
 759                 }




 760                 return null;
 761             }
 762 
 763             bufferedFragments.remove(rFrag);    // popup the fragment
 764 
 765             ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment);
 766             ByteBuffer plaintextFragment = null;
 767             try {
 768                 plaintextFragment = decrypt(readAuthenticator, readCipher,
 769                         rFrag.contentType, fragment, rFrag.recordEnS);
 770             } catch (BadPaddingException bpe) {
 771                 if (debug != null && Debug.isOn("ssl")) {
 772                     System.out.println(Thread.currentThread().getName() +
 773                             " discard invalid record: " + bpe);
 774                 }
 775 
 776                 // invalid, discard this record [section 4.1.2.7, RFC 6347]
 777                 return null;
 778             }
 779 
 780             // The ciphtext handshake message can only be Finished (the
 781             // end of this flight), ClinetHello or HelloRequest (the
 782             // beginning of the next flight) message.  Need not to check
 783             // any ChangeCipherSpec message.
 784             if (rFrag.contentType == Record.ct_handshake) {
 785                 HandshakeFragment finFrag = null;
 786                 while (plaintextFragment.remaining() > 0) {
 787                     HandshakeFragment hsFrag = parseHandshakeMessage(
 788                             rFrag.contentType,
 789                             rFrag.majorVersion, rFrag.minorVersion,
 790                             rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq,
 791                             plaintextFragment);
 792 
 793                     if (hsFrag == null) {
 794                         // invalid, discard this record





 795                         return null;
 796                     }
 797 
 798                     if (hsFrag.handshakeType == HandshakeMessage.ht_finished) {
 799                         finFrag = hsFrag;
 800 
 801                         // reset for the next flight
 802                         this.flightType = (byte)0xFF;
 803                         this.flightTopEpoch = rFrag.recordEpoch;
 804                         this.flightTopMessageSeq = hsFrag.messageSeq + 1;
 805                         this.flightTopRecordSeq = -1;
 806                     } else {
 807                         // reset the flight
 808                         if (flightIsReady) {
 809                             flightIsReady = false;

 810                         }
 811                         queueUpHandshake(hsFrag);
 812                     }
 813                 }
 814 
 815                 this.nextRecordSeq = rFrag.recordSeq + 1;
 816                 this.nextMessageSeq = 0;
 817 
 818                 if (finFrag != null) {
 819                     this.nextRecordEpoch = finFrag.recordEpoch;
 820                     this.nextRecordSeq = finFrag.recordSeq + 1;
 821                     this.nextMessageSeq = finFrag.messageSeq + 1;
 822 
 823                     // Finished message does not fragment.
 824                     byte[] recordFrag = new byte[finFrag.messageLength + 4];
 825                     Plaintext plaintext = new Plaintext(finFrag.contentType,
 826                             finFrag.majorVersion, finFrag.minorVersion,
 827                             finFrag.recordEpoch, finFrag.recordSeq,
 828                             ByteBuffer.wrap(recordFrag));
 829 
 830                     // fill the handshake fragment of the record
 831                     recordFrag[0] = finFrag.handshakeType;
 832                     recordFrag[1] =
 833                             (byte)((finFrag.messageLength >>> 16) & 0xFF);
 834                     recordFrag[2] =
 835                             (byte)((finFrag.messageLength >>> 8) & 0xFF);
 836                     recordFrag[3] = (byte)(finFrag.messageLength & 0xFF);
 837 
 838                     System.arraycopy(finFrag.fragment, 0,
 839                             recordFrag, 4, finFrag.fragmentLength);
 840 
 841                     // handshake hashing
 842                     handshakeHashing(finFrag, plaintext);
 843 
 844                     // input handshake finished
 845                     handshakeFinished = true;
 846 
 847                     return plaintext;
 848                 } else {
 849                     return acquirePlaintext();
 850                 }
 851             } else {
 852                 return new Plaintext(rFrag.contentType,
 853                         rFrag.majorVersion, rFrag.minorVersion,
 854                         rFrag.recordEpoch, rFrag.recordSeq,

 855                         plaintextFragment);
 856             }
 857         }
 858 
 859         private Plaintext acquireHandshakeMessage() {
 860 
 861             RecordFragment rFrag = bufferedFragments.first();
 862             if (rFrag.contentType == Record.ct_change_cipher_spec) {
 863                 this.nextRecordEpoch = rFrag.recordEpoch + 1;





 864                 this.nextRecordSeq = 0;
 865                 // no change on next handshake message sequence number
 866 
 867                 bufferedFragments.remove(rFrag);        // popup the fragment

 868 
 869                 // Reload if this message has been reserved for handshake hash.
 870                 handshakeHash.reload();
 871 
 872                 return new Plaintext(rFrag.contentType,
 873                         rFrag.majorVersion, rFrag.minorVersion,
 874                         rFrag.recordEpoch, rFrag.recordSeq,

 875                         ByteBuffer.wrap(rFrag.fragment));
 876             } else {    // rFrag.contentType == Record.ct_handshake
 877                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
 878                 if ((hsFrag.messageLength == hsFrag.fragmentLength) &&
 879                     (hsFrag.fragmentOffset == 0)) {     // no fragmentation
 880 
 881                     bufferedFragments.remove(rFrag);    // popup the fragment
 882 
 883                     // this.nextRecordEpoch = hsFrag.recordEpoch;
 884                     this.nextRecordSeq = hsFrag.recordSeq + 1;
 885                     this.nextMessageSeq = hsFrag.messageSeq + 1;
 886 
 887                     // Note: may try to avoid byte array copy in the future.
 888                     byte[] recordFrag = new byte[hsFrag.messageLength + 4];
 889                     Plaintext plaintext = new Plaintext(hsFrag.contentType,
 890                             hsFrag.majorVersion, hsFrag.minorVersion,
 891                             hsFrag.recordEpoch, hsFrag.recordSeq,

 892                             ByteBuffer.wrap(recordFrag));
 893 
 894                     // fill the handshake fragment of the record
 895                     recordFrag[0] = hsFrag.handshakeType;
 896                     recordFrag[1] =
 897                             (byte)((hsFrag.messageLength >>> 16) & 0xFF);
 898                     recordFrag[2] =
 899                             (byte)((hsFrag.messageLength >>> 8) & 0xFF);
 900                     recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
 901 
 902                     System.arraycopy(hsFrag.fragment, 0,
 903                             recordFrag, 4, hsFrag.fragmentLength);
 904 
 905                     // handshake hashing
 906                     handshakeHashing(hsFrag, plaintext);
 907 
 908                     return plaintext;
 909                 } else {                // fragmented handshake message
 910                     // the first record
 911                     //
 912                     // Note: may try to avoid byte array copy in the future.
 913                     byte[] recordFrag = new byte[hsFrag.messageLength + 4];
 914                     Plaintext plaintext = new Plaintext(hsFrag.contentType,
 915                             hsFrag.majorVersion, hsFrag.minorVersion,
 916                             hsFrag.recordEpoch, hsFrag.recordSeq,

 917                             ByteBuffer.wrap(recordFrag));
 918 
 919                     // fill the handshake fragment of the record
 920                     recordFrag[0] = hsFrag.handshakeType;
 921                     recordFrag[1] =
 922                             (byte)((hsFrag.messageLength >>> 16) & 0xFF);
 923                     recordFrag[2] =
 924                             (byte)((hsFrag.messageLength >>> 8) & 0xFF);
 925                     recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
 926 
 927                     int msgSeq = hsFrag.messageSeq;
 928                     long maxRecodeSN = hsFrag.recordSeq;
 929                     HandshakeFragment hmFrag = hsFrag;
 930                     do {
 931                         System.arraycopy(hmFrag.fragment, 0,
 932                                 recordFrag, hmFrag.fragmentOffset + 4,
 933                                 hmFrag.fragmentLength);
 934                         // popup the fragment
 935                         bufferedFragments.remove(rFrag);
 936 


 940 
 941                         // Note: may buffer retransmitted fragments in order to
 942                         // speed up the reassembly in the future.
 943 
 944                         // read the next buffered record
 945                         if (!bufferedFragments.isEmpty()) {
 946                             rFrag = bufferedFragments.first();
 947                             if (rFrag.contentType != Record.ct_handshake) {
 948                                 break;
 949                             } else {
 950                                 hmFrag = (HandshakeFragment)rFrag;
 951                             }
 952                         }
 953                     } while (!bufferedFragments.isEmpty() &&
 954                             (msgSeq == hmFrag.messageSeq));
 955 
 956                     // handshake hashing
 957                     handshakeHashing(hsFrag, plaintext);
 958 
 959                     this.nextRecordSeq = maxRecodeSN + 1;
 960                     this.nextMessageSeq = msgSeq + 1;
 961 
 962                     return plaintext;
 963                 }
 964             }
 965         }
 966 
 967         boolean flightIsReady() {
 968 


 969             //
 970             // the ChangeCipherSpec/Finished flight
 971             //
 972             if (expectCCSFlight) {
 973                 // Have the ChangeCipherSpec/Finished messages been received?
 974                 return hasFinisedMessage(bufferedFragments);



 975             }
 976 
 977             if (flightType == (byte)0xFF) {






 978                 return false;
 979             }
 980 
 981             if ((flightType == HandshakeMessage.ht_client_hello) ||
 982                 (flightType == HandshakeMessage.ht_hello_request) ||
 983                 (flightType == HandshakeMessage.ht_hello_verify_request)) {
 984 
 985                 // single handshake message flight
 986                 return hasCompleted(holesMap.get(flightType));


 987             }
 988 



 989             //
 990             // the ServerHello flight
 991             //
 992             if (flightType == HandshakeMessage.ht_server_hello) {
 993                 // Firstly, check the first flight handshake message.
 994                 if (!hasCompleted(holesMap.get(flightType))) {





 995                     return false;
 996                 }
 997 
 998                 //
 999                 // an abbreviated handshake
1000                 //
1001                 if (isAbbreviatedHandshake) {
1002                     // Ready to use the flight if received the
1003                     // ChangeCipherSpec and Finished messages.
1004                     return hasFinisedMessage(bufferedFragments);
1005                 }
1006 



1007                 //
1008                 // a full handshake
1009                 //
1010                 if (lastHandshakeFragment.handshakeType !=
1011                         HandshakeMessage.ht_server_hello_done) {

1012                     // Not yet got the final message of the flight.




1013                     return false;
1014                 }
1015 
1016                 // Have all handshake message been received?
1017                 return hasCompleted(bufferedFragments,
1018                     flightTopMessageSeq, lastHandshakeFragment.messageSeq);






1019             }
1020 



1021             //
1022             // the ClientKeyExchange flight
1023             //
1024             // Note: need to consider more messages in this flight if
1025             //       ht_supplemental_data and ht_certificate_url are
1026             //       suppported in the future.
1027             //
1028             if ((flightType == HandshakeMessage.ht_certificate) ||
1029                 (flightType == HandshakeMessage.ht_client_key_exchange)) {
1030 
1031                 // Firstly, check the first flight handshake message.
1032                 if (!hasCompleted(holesMap.get(flightType))) {
1033                     return false;



1034                 }
1035 
1036                 if (!hasFinisedMessage(bufferedFragments)) {
1037                     // not yet got the ChangeCipherSpec/Finished messages
1038                     return false;
1039                 }
1040 
1041                 if (flightType == HandshakeMessage.ht_client_key_exchange) {
1042                     // single handshake message flight
1043                     return true;



1044                 }
1045 
1046                 //
1047                 // flightType == HandshakeMessage.ht_certificate
1048                 //
1049                 // We don't support certificates containing fixed
1050                 // Diffie-Hellman parameters.  Therefore, CertificateVerify
1051                 // message is required if client Certificate message presents.
1052                 //
1053                 if (lastHandshakeFragment.handshakeType !=
1054                         HandshakeMessage.ht_certificate_verify) {
1055                     // Not yet got the final message of the flight.
1056                     return false;
1057                 }
1058 
1059                 // Have all handshake message been received?
1060                 return hasCompleted(bufferedFragments,
1061                     flightTopMessageSeq, lastHandshakeFragment.messageSeq);






1062             }
1063 



1064             //
1065             // Otherwise, need to receive more handshake messages.
1066             //




1067             return false;
1068         }
1069 
1070         private boolean isSessionResuming(
1071                 byte[] fragment, byte[] prevSid) throws SSLException {
1072 
1073             // As the first fragment of ServerHello should be big enough
1074             // to hold the session_id field, need not to worry about the
1075             // fragmentation here.
1076             if ((fragment == null) || (fragment.length < 38)) {
1077                                     // 38: the minimal ServerHello body length
1078                 throw new SSLException(
1079                         "Invalid ServerHello message: no sufficient data");
1080             }
1081 

1082             int sidLen = fragment[34];          // 34: the length field
1083             if (sidLen > 32) {                  // opaque SessionID<0..32>
1084                 throw new SSLException(
1085                         "Invalid ServerHello message: invalid session id");
1086             }
1087 
1088             if (fragment.length < 38 + sidLen) {
1089                 throw new SSLException(
1090                         "Invalid ServerHello message: no sufficient data");
1091             }
1092 
1093             if (sidLen != 0 && (prevSid.length == sidLen)) {
1094                 // may be a session-resuming handshake
1095                 for (int i = 0; i < sidLen; i++) {
1096                     if (prevSid[i] != fragment[35 + i]) {
1097                                                 // 35: the session identifier
1098                         return false;
1099                     }
1100                 }
1101 
1102                 return true;
1103             }


1105             return false;
1106         }
1107 
1108         private byte[] getSessionID(byte[] fragment) {
1109             // The validity has been checked in the call to isSessionResuming().
1110             int sidLen = fragment[34];      // 34: the sessionID length field
1111 
1112             byte[] temporary = new byte[sidLen];
1113             System.arraycopy(fragment, 35, temporary, 0, sidLen);
1114 
1115             return temporary;
1116         }
1117 
1118         // Looking for the ChangeCipherSpec and Finished messages.
1119         //
1120         // As the cached Finished message should be a ciphertext, we don't
1121         // exactly know a ciphertext is a Finished message or not.  According
1122         // to the spec of TLS/DTLS handshaking, a Finished message is always
1123         // sent immediately after a ChangeCipherSpec message.  The first
1124         // ciphertext handshake message should be the expected Finished message.
1125         private boolean hasFinisedMessage(
1126                 Set<RecordFragment> fragments) {
1127 
1128             boolean hasCCS = false;
1129             boolean hasFin = false;
1130             for (RecordFragment fragment : fragments) {
1131                 if (fragment.contentType == Record.ct_change_cipher_spec) {
1132                     if (hasFin) {
1133                         return true;
1134                     }
1135                     hasCCS = true;
1136                 } else if (fragment.contentType == Record.ct_handshake) {
1137                     // Finished is the first expected message of a new epoch.
1138                     if (fragment.isCiphertext) {
1139                         if (hasCCS) {
1140                             return true;
1141                         }
1142                         hasFin = true;
1143                     }
1144                 }
1145             }
1146 
1147             return hasFin && hasCCS;
1148         }
1149 
1150         private boolean hasCompleted(List<HoleDescriptor> holes) {


1151             if (holes == null) {
1152                 // not yet received this kind of handshake message
1153                 return false;
1154             }
1155 
1156             return holes.isEmpty();  // no fragment hole for complete message
1157         }
1158 
1159         private boolean hasCompleted(
1160                 Set<RecordFragment> fragments,
1161                 int presentMsgSeq, int endMsgSeq) {
1162 
1163             // The caller should have checked the completion of the first
1164             // present handshake message.  Need not to check it again.
1165             for (RecordFragment rFrag : fragments) {
1166                 if ((rFrag.contentType != Record.ct_handshake) ||
1167                         rFrag.isCiphertext) {
1168                     break;
1169                 }
1170 
1171                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
1172                 if (hsFrag.messageSeq == presentMsgSeq) {
1173                     continue;
1174                 } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) {
1175                     // check the completion of the handshake message
1176                     if (!hasCompleted(holesMap.get(hsFrag.handshakeType))) {
1177                         return false;
1178                     }
1179 
1180                     presentMsgSeq = hsFrag.messageSeq;
1181                 } else {
1182                     // not yet got handshake message next to presentMsgSeq
1183                     break;
1184                 }
1185             }
1186 
1187             return (presentMsgSeq >= endMsgSeq);
1188                         // false: if not yet got all messages of the flight.
1189         }
1190 
1191         private void handshakeHashing(
1192                 HandshakeFragment hsFrag, Plaintext plaintext) {
1193 
1194             byte hsType = hsFrag.handshakeType;
1195             if ((hsType == HandshakeMessage.ht_hello_request) ||
1196                 (hsType == HandshakeMessage.ht_hello_verify_request)) {


   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


  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();


  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 


 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;


 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 


1260 
1261                         // Note: may buffer retransmitted fragments in order to
1262                         // speed up the reassembly in the future.
1263 
1264                         // read the next buffered record
1265                         if (!bufferedFragments.isEmpty()) {
1266                             rFrag = bufferedFragments.first();
1267                             if (rFrag.contentType != Record.ct_handshake) {
1268                                 break;
1269                             } else {
1270                                 hmFrag = (HandshakeFragment)rFrag;
1271                             }
1272                         }
1273                     } while (!bufferedFragments.isEmpty() &&
1274                             (msgSeq == hmFrag.messageSeq));
1275 
1276                     // handshake hashing
1277                     handshakeHashing(hsFrag, plaintext);
1278 
1279                     this.nextRecordSeq = maxRecodeSN + 1;

1280 
1281                     return plaintext;
1282                 }
1283             }
1284         }
1285 
1286         boolean flightIsReady() {
1287 
1288             byte flightType = handshakeFlight.handshakeType;
1289             if (flightType == HandshakeFlight.HF_UNKNOWN) {
1290                 //
1291                 // the ChangeCipherSpec/Finished flight
1292                 //
1293                 if (expectCCSFlight) {
1294                     // Have the ChangeCipherSpec/Finished flight been received?
1295                     boolean isReady = hasFinishedMessage(bufferedFragments);
1296                     if (debug != null && Debug.isOn("verbose")) {
1297                         Debug.log(
1298                             "Has the final flight been received? " + isReady);
1299                     }
1300 
1301                     return isReady;
1302                 }
1303 
1304                 if (debug != null && Debug.isOn("verbose")) {
1305                     Debug.log("No flight is received yet.");
1306                 }
1307 
1308                 return false;
1309             }
1310 
1311             if ((flightType == HandshakeMessage.ht_client_hello) ||
1312                 (flightType == HandshakeMessage.ht_hello_request) ||
1313                 (flightType == HandshakeMessage.ht_hello_verify_request)) {
1314 
1315                 // single handshake message flight
1316                 boolean isReady = hasCompleted(flightType);
1317                 if (debug != null && Debug.isOn("verbose")) {
1318                     Debug.log("Is the handshake message completed? " + isReady);
1319                 }
1320 
1321                 return isReady;
1322             }
1323 
1324             //
1325             // the ServerHello flight
1326             //
1327             if (flightType == HandshakeMessage.ht_server_hello) {
1328                 // Firstly, check the first flight handshake message.
1329                 if (!hasCompleted(flightType)) {
1330                     if (debug != null && Debug.isOn("verbose")) {
1331                         Debug.log(
1332                             "The ServerHello message is not completed yet.");
1333                     }
1334 
1335                     return false;
1336                 }
1337 
1338                 //
1339                 // an abbreviated handshake
1340                 //
1341                 if (hasFinishedMessage(bufferedFragments)) {
1342                     if (debug != null && Debug.isOn("verbose")) {
1343                         Debug.log("It's an abbreviated handshake.");

1344                     }
1345 
1346                     return true;
1347                 }
1348 
1349                 //
1350                 // a full handshake
1351                 //
1352                 List<HoleDescriptor> holes = handshakeFlight.holesMap.get(
1353                         HandshakeMessage.ht_server_hello_done);
1354                 if ((holes == null) || !holes.isEmpty()) {
1355                     // Not yet got the final message of the flight.
1356                     if (debug != null && Debug.isOn("verbose")) {
1357                         Debug.log("Not yet got the ServerHelloDone message");
1358                     }
1359 
1360                     return false;
1361                 }
1362 
1363                 // Have all handshake message been received?
1364                 boolean isReady = hasCompleted(bufferedFragments,
1365                             handshakeFlight.minMessageSeq,
1366                             handshakeFlight.maxMessageSeq);
1367                 if (debug != null && Debug.isOn("verbose")) {
1368                     Debug.log("Is the ServerHello flight (message " +
1369                             handshakeFlight.minMessageSeq + "-" +
1370                             handshakeFlight.maxMessageSeq +
1371                             ") completed? " + isReady);
1372                 }
1373 
1374                 return isReady;
1375             }
1376 
1377             //
1378             // the ClientKeyExchange flight
1379             //
1380             // Note: need to consider more messages in this flight if
1381             //       ht_supplemental_data and ht_certificate_url are
1382             //       suppported in the future.
1383             //
1384             if ((flightType == HandshakeMessage.ht_certificate) ||
1385                 (flightType == HandshakeMessage.ht_client_key_exchange)) {
1386 
1387                 // Firstly, check the first flight handshake message.
1388                 if (!hasCompleted(flightType)) {
1389                     if (debug != null && Debug.isOn("verbose")) {
1390                         Debug.log(
1391                             "The ClientKeyExchange or client Certificate " +
1392                             "message is not completed yet.");
1393                     }
1394 


1395                     return false;
1396                 }
1397 
1398                 if (!hasFinishedMessage(bufferedFragments)) {
1399                     // not yet have the ChangeCipherSpec/Finished messages
1400                     if (debug != null && Debug.isOn("verbose")) {
1401                         Debug.log(
1402                             "Not yet have the ChangeCipherSpec and " +
1403                             "Finished messages");
1404                     }
1405 










1406                     return false;
1407                 }
1408 
1409                 // Have all handshake message been received?
1410                 boolean isReady = hasCompleted(bufferedFragments,
1411                             handshakeFlight.minMessageSeq,
1412                             handshakeFlight.maxMessageSeq);
1413                 if (debug != null && Debug.isOn("verbose")) {
1414                     Debug.log("Is the ClientKeyExchange flight (message " +
1415                             handshakeFlight.minMessageSeq + "-" +
1416                             handshakeFlight.maxMessageSeq +
1417                             ") completed? " + isReady);
1418                 }
1419 
1420                 return isReady;
1421             }
1422 
1423             //
1424             // Otherwise, need to receive more handshake messages.
1425             //
1426             if (debug != null && Debug.isOn("verbose")) {
1427                 Debug.log("Need to receive more handshake messages");
1428             }
1429 
1430             return false;
1431         }
1432 
1433         private boolean isSessionResuming(
1434                 byte[] fragment, byte[] prevSid) throws SSLException {
1435 
1436             // As the first fragment of ServerHello should be big enough
1437             // to hold the session_id field, need not to worry about the
1438             // fragmentation here.
1439             if ((fragment == null) || (fragment.length < 38)) {
1440                                     // 38: the minimal ServerHello body length
1441                 throw new SSLException(
1442                         "Invalid ServerHello message: no sufficient data");
1443             }
1444 
1445             // SessionId.MAX_LENGTH is 32.
1446             int sidLen = fragment[34];          // 34: the length field
1447             if (sidLen > 32) {                  // opaque SessionID<0, 32>
1448                 throw new SSLException(
1449                         "Invalid ServerHello message: invalid session id");
1450             }
1451 
1452             if (fragment.length < 38 + sidLen) {
1453                 throw new SSLException(
1454                         "Invalid ServerHello message: no sufficient data");
1455             }
1456 
1457             if (sidLen != 0 && (prevSid.length == sidLen)) {
1458                 // may be a session-resuming handshake
1459                 for (int i = 0; i < sidLen; i++) {
1460                     if (prevSid[i] != fragment[35 + i]) {
1461                                                 // 35: the session identifier
1462                         return false;
1463                     }
1464                 }
1465 
1466                 return true;
1467             }


1469             return false;
1470         }
1471 
1472         private byte[] getSessionID(byte[] fragment) {
1473             // The validity has been checked in the call to isSessionResuming().
1474             int sidLen = fragment[34];      // 34: the sessionID length field
1475 
1476             byte[] temporary = new byte[sidLen];
1477             System.arraycopy(fragment, 35, temporary, 0, sidLen);
1478 
1479             return temporary;
1480         }
1481 
1482         // Looking for the ChangeCipherSpec and Finished messages.
1483         //
1484         // As the cached Finished message should be a ciphertext, we don't
1485         // exactly know a ciphertext is a Finished message or not.  According
1486         // to the spec of TLS/DTLS handshaking, a Finished message is always
1487         // sent immediately after a ChangeCipherSpec message.  The first
1488         // ciphertext handshake message should be the expected Finished message.
1489         private boolean hasFinishedMessage(
1490                 Set<RecordFragment> fragments) {
1491 
1492             boolean hasCCS = false;
1493             boolean hasFin = false;
1494             for (RecordFragment fragment : fragments) {
1495                 if (fragment.contentType == Record.ct_change_cipher_spec) {
1496                     if (hasFin) {
1497                         return true;
1498                     }
1499                     hasCCS = true;
1500                 } else if (fragment.contentType == Record.ct_handshake) {
1501                     // Finished is the first expected message of a new epoch.
1502                     if (fragment.isCiphertext) {
1503                         if (hasCCS) {
1504                             return true;
1505                         }
1506                         hasFin = true;
1507                     }
1508                 }
1509             }
1510 
1511             return hasFin && hasCCS;
1512         }
1513 
1514         private boolean hasCompleted(byte handshakeType) {
1515             List<HoleDescriptor> holes =
1516                     handshakeFlight.holesMap.get(handshakeType);
1517             if (holes == null) {
1518                 // not yet received this kind of handshake message
1519                 return false;
1520             }
1521 
1522             return holes.isEmpty();  // no fragment hole for complete message
1523         }
1524 
1525         private boolean hasCompleted(
1526                 Set<RecordFragment> fragments,
1527                 int presentMsgSeq, int endMsgSeq) {
1528 
1529             // The caller should have checked the completion of the first
1530             // present handshake message.  Need not to check it again.
1531             for (RecordFragment rFrag : fragments) {
1532                 if ((rFrag.contentType != Record.ct_handshake) ||
1533                         rFrag.isCiphertext) {
1534                     break;
1535                 }
1536 
1537                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
1538                 if (hsFrag.messageSeq == presentMsgSeq) {
1539                     continue;
1540                 } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) {
1541                     // check the completion of the handshake message
1542                     if (!hasCompleted(hsFrag.handshakeType)) {
1543                         return false;
1544                     }
1545 
1546                     presentMsgSeq = hsFrag.messageSeq;
1547                 } else {
1548                     // not yet got handshake message next to presentMsgSeq
1549                     break;
1550                 }
1551             }
1552 
1553             return (presentMsgSeq >= endMsgSeq);
1554                         // false: if not yet got all messages of the flight.
1555         }
1556 
1557         private void handshakeHashing(
1558                 HandshakeFragment hsFrag, Plaintext plaintext) {
1559 
1560             byte hsType = hsFrag.handshakeType;
1561             if ((hsType == HandshakeMessage.ht_hello_request) ||
1562                 (hsType == HandshakeMessage.ht_hello_verify_request)) {