< prev index next >

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

Print this page


   1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.*;
  29 import java.nio.*;

  30 import java.util.*;
  31 import javax.crypto.BadPaddingException;
  32 
  33 import javax.net.ssl.*;
  34 
  35 import sun.security.util.HexDumpEncoder;
  36 import static sun.security.ssl.HandshakeMessage.*;
  37 
  38 /**
  39  * DTLS {@code InputRecord} implementation for {@code SSLEngine}.
  40  */
  41 final class DTLSInputRecord extends InputRecord implements DTLSRecord {
  42 
  43     private DTLSReassembler reassembler = null;

  44 
  45     int                 readEpoch;
  46 
  47     int                 prevReadEpoch;
  48     Authenticator       prevReadAuthenticator;
  49     CipherBox           prevReadCipher;
  50 
  51     DTLSInputRecord() {
  52         this.readEpoch = 0;
  53         this.readAuthenticator = new MAC(true);
  54 
  55         this.prevReadEpoch = 0;
  56         this.prevReadCipher = CipherBox.NULL;
  57         this.prevReadAuthenticator = new MAC(true);
  58     }
  59 
  60     @Override
  61     void changeReadCiphers(Authenticator readAuthenticator,
  62             CipherBox readCipher) {
  63 
  64         prevReadCipher.dispose();
  65 
  66         this.prevReadAuthenticator = this.readAuthenticator;
  67         this.prevReadCipher = this.readCipher;
  68         this.prevReadEpoch = this.readEpoch;
  69 
  70         this.readAuthenticator = readAuthenticator;
  71         this.readCipher = readCipher;
  72         this.readEpoch++;
  73     }
  74 
  75     @Override
  76     public synchronized void close() throws IOException {
  77         if (!isClosed) {
  78             prevReadCipher.dispose();
  79             super.close();
  80         }
  81     }
  82 
  83     @Override
  84     boolean isEmpty() {
  85         return ((reassembler == null) || reassembler.isEmpty());
  86     }
  87 
  88     @Override
  89     int estimateFragmentSize(int packetSize) {
  90         int macLen = 0;
  91         if (readAuthenticator instanceof MAC) {
  92             macLen = ((MAC)readAuthenticator).MAClen();
  93         }
  94 
  95         if (packetSize > 0) {
  96             return readCipher.estimateFragmentSize(
  97                     packetSize, macLen, headerSize);
  98         } else {
  99             return Record.maxDataSize;
 100         }
 101     }
 102 
 103     @Override
 104     void expectingFinishFlight() {
 105         if (reassembler != null) {
 106             reassembler.expectingFinishFlight();
 107         }
 108     }
 109 
 110     @Override





 111     Plaintext acquirePlaintext() {
 112         if (reassembler != null) {
 113             return reassembler.acquirePlaintext();
 114         }
 115 
 116         return null;
 117     }
 118 
 119     @Override
 120     Plaintext decode(ByteBuffer packet) {












 121 

 122         if (isClosed) {
 123             return null;
 124         }
 125 
 126         if (debug != null && Debug.isOn("packet")) {
 127              Debug.printHex(
 128                     "[Raw read]: length = " + packet.remaining(), packet);
 129         }
 130 
 131         // The caller should have validated the record.
 132         int srcPos = packet.position();
 133         int srcLim = packet.limit();
 134 
 135         byte contentType = packet.get();                   // pos: 0
 136         byte majorVersion = packet.get();                  // pos: 1
 137         byte minorVersion = packet.get();                  // pos: 2
 138         byte[] recordEnS = new byte[8];                    // epoch + seqence
 139         packet.get(recordEnS);
 140         int recordEpoch = ((recordEnS[0] & 0xFF) << 8) |
 141                            (recordEnS[1] & 0xFF);          // pos: 3, 4
 142         long recordSeq  = ((recordEnS[2] & 0xFFL) << 40) |
 143                           ((recordEnS[3] & 0xFFL) << 32) |
 144                           ((recordEnS[4] & 0xFFL) << 24) |
 145                           ((recordEnS[5] & 0xFFL) << 16) |
 146                           ((recordEnS[6] & 0xFFL) <<  8) |
 147                            (recordEnS[7] & 0xFFL);         // pos: 5-10
 148 
 149         int contentLen = ((packet.get() & 0xFF) << 8) |
 150                           (packet.get() & 0xFF);           // pos: 11, 12
 151 
 152         if (debug != null && Debug.isOn("record")) {
 153             Debug.log("READ: " +
 154                     ProtocolVersion.valueOf(majorVersion, minorVersion) +
 155                     " " + Record.contentName(contentType) + ", length = " +
 156                     contentLen);
 157         }
 158 
 159         int recLim = srcPos + DTLSRecord.headerSize + contentLen;
 160 
 161         if (this.prevReadEpoch > recordEpoch) {
 162             // Reset the position of the packet buffer.
 163             packet.position(recLim);
 164             if (debug != null && Debug.isOn("record")) {
 165                 Debug.printHex("READ: discard this old record", recordEnS);
 166             }
 167             return null;
 168         }
 169 
 170         // Buffer next epoch message if necessary.
 171         if (this.readEpoch < recordEpoch) {
 172             // Discard the record younger than the current epcoh if:
 173             // 1. it is not a handshake message, or
 174             // 2. it is not of next epoch.
 175             if (((contentType != Record.ct_handshake) &&
 176                     (contentType != Record.ct_change_cipher_spec)) ||


 177                 (this.readEpoch < (recordEpoch - 1))) {
 178 
 179                 packet.position(recLim);
 180 
 181                 if (debug != null && Debug.isOn("verbose")) {
 182                     Debug.log("Premature record (epoch), discard it.");
 183                 }
 184 
 185                 return null;
 186             }
 187 

 188             // Not ready to decrypt this record, may be an encrypted Finished
 189             // message, need to buffer it.
 190             byte[] fragment = new byte[contentLen];
 191             packet.get(fragment);              // copy the fragment
 192             RecordFragment buffered = new RecordFragment(fragment, contentType,
 193                     majorVersion, minorVersion,
 194                     recordEnS, recordEpoch, recordSeq, true);
 195 



 196             reassembler.queueUpFragment(buffered);
 197 
 198             // consume the full record in the packet buffer.
 199             packet.position(recLim);
 200 
 201             return reassembler.acquirePlaintext();

 202         }
 203 
 204         //
 205         // Now, the message is of this epoch or the previous epoch.
 206         //
 207         Authenticator decodeAuthenticator;
 208         CipherBox decodeCipher;
 209         if (this.readEpoch == recordEpoch) {
 210             decodeAuthenticator = readAuthenticator;
 211             decodeCipher = readCipher;
 212         } else {                        // prevReadEpoch == recordEpoch
 213             decodeAuthenticator = prevReadAuthenticator;
 214             decodeCipher = prevReadCipher;
 215         }
 216 
 217         // decrypt the fragment
 218         packet.limit(recLim);
 219         packet.position(srcPos + DTLSRecord.headerSize);
 220 
 221         ByteBuffer plaintextFragment;
 222         try {
 223             plaintextFragment = decrypt(decodeAuthenticator,
 224                     decodeCipher, contentType, packet, recordEnS);
 225         } catch (BadPaddingException bpe) {
 226             if (debug != null && Debug.isOn("ssl")) {
 227                 Debug.log("Discard invalid record: " + bpe);


 228             }
 229 
 230             // invalid, discard this record [section 4.1.2.7, RFC 6347]
 231             return null;
 232         } finally {
 233             // comsume a complete record
 234             packet.limit(srcLim);
 235             packet.position(recLim);
 236         }
 237 
 238         if (contentType != Record.ct_change_cipher_spec &&
 239             contentType != Record.ct_handshake) {   // app data or alert
 240                                                     // no retransmission
 241             // Cleanup the handshake reassembler if necessary.
 242             if ((reassembler != null) &&
 243                     (reassembler.handshakeEpoch < recordEpoch)) {
 244                 if (debug != null && Debug.isOn("verbose")) {
 245                     Debug.log("Cleanup the handshake reassembler");
 246                 }
 247 
 248                 reassembler = null;
 249             }
 250 
 251             return new Plaintext(contentType, majorVersion, minorVersion,

 252                     recordEpoch, Authenticator.toLong(recordEnS),
 253                     plaintextFragment);
 254         }
 255 
 256         if (contentType == Record.ct_change_cipher_spec) {
 257             if (reassembler == null) {
 258                 if (this.readEpoch != recordEpoch) {
 259                     // handshake has not started, should be an
 260                     // old handshake message, discard it.
 261 
 262                     if (debug != null && Debug.isOn("verbose")) {
 263                         Debug.log(
 264                                 "Lagging behind ChangeCipherSpec, discard it.");
 265                     }
 266 
 267                     return null;
 268                 }
 269 
 270                 reassembler = new DTLSReassembler(recordEpoch);
 271             }
 272 
 273             reassembler.queueUpChangeCipherSpec(
 274                     new RecordFragment(plaintextFragment, contentType,
 275                             majorVersion, minorVersion,
 276                             recordEnS, recordEpoch, recordSeq, false));
 277         } else {    // handshake record
 278             // One record may contain 1+ more handshake messages.
 279             while (plaintextFragment.remaining() > 0) {
 280 
 281                 HandshakeFragment hsFrag = parseHandshakeMessage(
 282                     contentType, majorVersion, minorVersion,
 283                     recordEnS, recordEpoch, recordSeq, plaintextFragment);
 284 
 285                 if (hsFrag == null) {
 286                     // invalid, discard this record
 287                     if (debug != null && Debug.isOn("verbose")) {
 288                         Debug.log("Invalid handshake message, discard it.");

 289                     }
 290 
 291                     return null;
 292                 }
 293 
 294                 if (reassembler == null) {
 295                     if (this.readEpoch != recordEpoch) {
 296                         // handshake has not started, should be an
 297                         // old handshake message, discard it.
 298 
 299                         if (debug != null && Debug.isOn("verbose")) {
 300                             Debug.log(
 301                                 "Lagging behind handshake record, discard it.");
 302                         }
 303 
 304                         return null;
 305                     }
 306 
 307                     reassembler = new DTLSReassembler(recordEpoch);
 308                 }
 309 
 310                 reassembler.queueUpHandshake(hsFrag);
 311             }
 312         }
 313 
 314         // Completed the read of the full record.  Acquire the reassembled
 315         // messages.
 316         if (reassembler != null) {
 317             return reassembler.acquirePlaintext();

 318         }
 319 
 320         if (debug != null && Debug.isOn("verbose")) {
 321             Debug.log("The reassembler is not initialized yet.");
 322         }
 323 
 324         return null;
 325     }
 326 
 327     @Override
 328     int bytesInCompletePacket(ByteBuffer packet) throws SSLException {






 329 
 330         // DTLS length field is in bytes 11/12
 331         if (packet.remaining() < headerSize) {
 332             return -1;
 333         }
 334 
 335         // Last sanity check that it's not a wild record
 336         int pos = packet.position();
 337 
 338         // Check the content type of the record.
 339         byte contentType = packet.get(pos);
 340         if (!Record.isValidContentType(contentType)) {
 341             throw new SSLException(
 342                     "Unrecognized SSL message, plaintext connection?");
 343         }
 344 
 345         // Check the protocol version of the record.
 346         ProtocolVersion recordVersion =
 347             ProtocolVersion.valueOf(packet.get(pos + 1), packet.get(pos + 2));
 348         checkRecordVersion(recordVersion, false);





 349 
 350         // Get the fragment length of the record.
 351         int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) +
 352                        (packet.get(pos + 12) & 0xFF) + headerSize;
 353         if (fragLen > Record.maxFragmentSize) {
 354             throw new SSLException(
 355                     "Record overflow, fragment length (" + fragLen +
 356                     ") MUST not exceed " + Record.maxFragmentSize);
 357         }
 358 
 359         return fragLen;
 360     }
 361 
 362     @Override
 363     void checkRecordVersion(ProtocolVersion recordVersion,
 364             boolean allowSSL20Hello) throws SSLException {
 365 
 366         if (!recordVersion.maybeDTLSProtocol()) {
 367             throw new SSLException(
 368                     "Unrecognized record version " + recordVersion +
 369                     " , plaintext connection?");
 370         }
 371     }
 372 
 373     private static HandshakeFragment parseHandshakeMessage(
 374             byte contentType, byte majorVersion, byte minorVersion,
 375             byte[] recordEnS, int recordEpoch, long recordSeq,
 376             ByteBuffer plaintextFragment) {
 377 
 378         int remaining = plaintextFragment.remaining();
 379         if (remaining < handshakeHeaderSize) {
 380             if (debug != null && Debug.isOn("ssl")) {
 381                 Debug.log("Discard invalid record: " +
 382                         "too small record to hold a handshake fragment");
 383             }
 384 
 385             // invalid, discard this record [section 4.1.2.7, RFC 6347]
 386             return null;
 387         }
 388 
 389         byte handshakeType = plaintextFragment.get();       // pos: 0
 390         int messageLength =
 391                 ((plaintextFragment.get() & 0xFF) << 16) |
 392                 ((plaintextFragment.get() & 0xFF) << 8) |
 393                  (plaintextFragment.get() & 0xFF);          // pos: 1-3
 394         int messageSeq =
 395                 ((plaintextFragment.get() & 0xFF) << 8) |
 396                  (plaintextFragment.get() & 0xFF);          // pos: 4/5
 397         int fragmentOffset =
 398                 ((plaintextFragment.get() & 0xFF) << 16) |
 399                 ((plaintextFragment.get() & 0xFF) << 8) |
 400                  (plaintextFragment.get() & 0xFF);          // pos: 6-8
 401         int fragmentLength =
 402                 ((plaintextFragment.get() & 0xFF) << 16) |
 403                 ((plaintextFragment.get() & 0xFF) << 8) |
 404                  (plaintextFragment.get() & 0xFF);          // pos: 9-11
 405         if ((remaining - handshakeHeaderSize) < fragmentLength) {
 406             if (debug != null && Debug.isOn("ssl")) {
 407                 Debug.log("Discard invalid record: " +
 408                         "not a complete handshake fragment in the record");
 409             }
 410 
 411             // invalid, discard this record [section 4.1.2.7, RFC 6347]
 412             return null;
 413         }
 414 
 415         byte[] fragment = new byte[fragmentLength];
 416         plaintextFragment.get(fragment);
 417 
 418         return new HandshakeFragment(fragment, contentType,
 419                 majorVersion, minorVersion,
 420                 recordEnS, recordEpoch, recordSeq,
 421                 handshakeType, messageLength,
 422                 messageSeq, fragmentOffset, fragmentLength);
 423     }
 424 
 425     // buffered record fragment
 426     private static class RecordFragment implements Comparable<RecordFragment> {
 427         boolean         isCiphertext;


 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         }


 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
 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 


 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 


 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.


 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) {


 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) {


1071             //
1072             // Note: actually, we need to do nothing because the reassembler
1073             // of handshake messages will reset them properly even for
1074             // retransmissions.
1075             //
1076             handshakeFlight.maxMessageSeq = 0;
1077             handshakeFlight.maxRecordEpoch = handshakeFlight.flightEpoch;
1078 
1079             // Record sequence number cannot wrap even for retransmissions.
1080             handshakeFlight.maxRecordSeq = prev.maxRecordSeq + 1;
1081 
1082             // cleanup holes map
1083             handshakeFlight.holesMap.clear();
1084 
1085             // Ready to accept new input record.
1086             flightIsReady = false;
1087             needToCheckFlight = false;
1088         }
1089 
1090         private Plaintext acquireCachedMessage() {
1091 
1092             RecordFragment rFrag = bufferedFragments.first();
1093             if (readEpoch != rFrag.recordEpoch) {
1094                 if (readEpoch > rFrag.recordEpoch) {
1095                     // discard old records
1096                     if (debug != null && Debug.isOn("verbose")) {
1097                         Debug.log("Discard old buffered ciphertext fragments.");

1098                     }
1099                     bufferedFragments.remove(rFrag);    // popup the fragment
1100                 }
1101 
1102                 // reset the flight
1103                 if (flightIsReady) {
1104                     flightIsReady = false;
1105                 }
1106 
1107                 if (debug != null && Debug.isOn("verbose")) {
1108                     Debug.log("Not yet ready to decrypt the cached fragments.");

1109                 }
1110                 return null;
1111             }
1112 
1113             bufferedFragments.remove(rFrag);    // popup the fragment
1114 
1115             ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment);
1116             ByteBuffer plaintextFragment = null;
1117             try {
1118                 plaintextFragment = decrypt(readAuthenticator, readCipher,
1119                         rFrag.contentType, fragment, rFrag.recordEnS);
1120             } catch (BadPaddingException bpe) {
1121                 if (debug != null && Debug.isOn("verbose")) {
1122                     Debug.log("Discard invalid record: " + bpe);


1123                 }
1124 
1125                 // invalid, discard this record [section 4.1.2.7, RFC 6347]
1126                 return null;
1127             }
1128 
1129             // The ciphtext handshake message can only be Finished (the
1130             // end of this flight), ClinetHello or HelloRequest (the
1131             // beginning of the next flight) message.  Need not to check
1132             // any ChangeCipherSpec message.
1133             if (rFrag.contentType == Record.ct_handshake) {
1134                 while (plaintextFragment.remaining() > 0) {
1135                     HandshakeFragment hsFrag = parseHandshakeMessage(
1136                             rFrag.contentType,
1137                             rFrag.majorVersion, rFrag.minorVersion,
1138                             rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq,
1139                             plaintextFragment);
1140 
1141                     if (hsFrag == null) {
1142                         // invalid, discard this record
1143                         if (debug != null && Debug.isOn("verbose")) {
1144                             Debug.printHex(
1145                                     "Invalid handshake fragment, discard it",
1146                                     plaintextFragment);
1147                         }
1148                         return null;
1149                     }
1150 
1151                     queueUpHandshake(hsFrag);
1152                     // The flight ready status (flightIsReady) should have
1153                     // been checked and updated for the Finished handshake
1154                     // message before the decryption.  Please don't update
1155                     // flightIsReady for Finished messages.
1156                     if (hsFrag.handshakeType != HandshakeMessage.ht_finished) {
1157                         flightIsReady = false;
1158                         needToCheckFlight = true;
1159                     }
1160                 }
1161 
1162                 return acquirePlaintext();
1163             } else {
1164                 return new Plaintext(rFrag.contentType,
1165                         rFrag.majorVersion, rFrag.minorVersion,
1166                         rFrag.recordEpoch,
1167                         Authenticator.toLong(rFrag.recordEnS),
1168                         plaintextFragment);
1169             }
1170         }
1171 
1172         private Plaintext acquireHandshakeMessage() {
1173 
1174             RecordFragment rFrag = bufferedFragments.first();
1175             if (rFrag.contentType == Record.ct_change_cipher_spec) {
1176                 this.nextRecordEpoch = rFrag.recordEpoch + 1;
1177 
1178                 // For retransmissions, the next record sequence number is a
1179                 // positive value.  Don't worry about it as the acquiring of
1180                 // the immediately followed Finished handshake message will
1181                 // reset the next record sequence number correctly.
1182                 this.nextRecordSeq = 0;
1183 
1184                 // Popup the fragment.
1185                 bufferedFragments.remove(rFrag);
1186 
1187                 // Reload if this message has been reserved for handshake hash.
1188                 handshakeHash.reload();
1189 
1190                 return new Plaintext(rFrag.contentType,
1191                         rFrag.majorVersion, rFrag.minorVersion,
1192                         rFrag.recordEpoch,
1193                         Authenticator.toLong(rFrag.recordEnS),
1194                         ByteBuffer.wrap(rFrag.fragment));
1195             } else {    // rFrag.contentType == Record.ct_handshake
1196                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
1197                 if ((hsFrag.messageLength == hsFrag.fragmentLength) &&
1198                     (hsFrag.fragmentOffset == 0)) {     // no fragmentation
1199 
1200                     bufferedFragments.remove(rFrag);    // popup the fragment
1201 
1202                     // this.nextRecordEpoch = hsFrag.recordEpoch;
1203                     this.nextRecordSeq = hsFrag.recordSeq + 1;
1204 
1205                     // Note: may try to avoid byte array copy in the future.
1206                     byte[] recordFrag = new byte[hsFrag.messageLength + 4];
1207                     Plaintext plaintext = new Plaintext(hsFrag.contentType,

1208                             hsFrag.majorVersion, hsFrag.minorVersion,
1209                             hsFrag.recordEpoch,
1210                             Authenticator.toLong(hsFrag.recordEnS),
1211                             ByteBuffer.wrap(recordFrag));
1212 
1213                     // fill the handshake fragment of the record
1214                     recordFrag[0] = hsFrag.handshakeType;
1215                     recordFrag[1] =
1216                             (byte)((hsFrag.messageLength >>> 16) & 0xFF);
1217                     recordFrag[2] =
1218                             (byte)((hsFrag.messageLength >>> 8) & 0xFF);
1219                     recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
1220 
1221                     System.arraycopy(hsFrag.fragment, 0,
1222                             recordFrag, 4, hsFrag.fragmentLength);
1223 
1224                     // handshake hashing
1225                     handshakeHashing(hsFrag, plaintext);
1226 
1227                     return plaintext;
1228                 } else {                // fragmented handshake message
1229                     // the first record
1230                     //
1231                     // Note: may try to avoid byte array copy in the future.
1232                     byte[] recordFrag = new byte[hsFrag.messageLength + 4];
1233                     Plaintext plaintext = new Plaintext(hsFrag.contentType,

1234                             hsFrag.majorVersion, hsFrag.minorVersion,
1235                             hsFrag.recordEpoch,
1236                             Authenticator.toLong(hsFrag.recordEnS),
1237                             ByteBuffer.wrap(recordFrag));
1238 
1239                     // fill the handshake fragment of the record
1240                     recordFrag[0] = hsFrag.handshakeType;
1241                     recordFrag[1] =
1242                             (byte)((hsFrag.messageLength >>> 16) & 0xFF);
1243                     recordFrag[2] =
1244                             (byte)((hsFrag.messageLength >>> 8) & 0xFF);
1245                     recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
1246 
1247                     int msgSeq = hsFrag.messageSeq;
1248                     long maxRecodeSN = hsFrag.recordSeq;
1249                     HandshakeFragment hmFrag = hsFrag;
1250                     do {
1251                         System.arraycopy(hmFrag.fragment, 0,
1252                                 recordFrag, hmFrag.fragmentOffset + 4,
1253                                 hmFrag.fragmentLength);
1254                         // popup the fragment
1255                         bufferedFragments.remove(rFrag);
1256 
1257                         if (maxRecodeSN < hmFrag.recordSeq) {
1258                             maxRecodeSN = hmFrag.recordSeq;
1259                         }
1260 
1261                         // Note: may buffer retransmitted fragments in order to
1262                         // speed up the reassembly in the future.
1263 
1264                         // read the next buffered record
1265                         if (!bufferedFragments.isEmpty()) {
1266                             rFrag = bufferedFragments.first();
1267                             if (rFrag.contentType != Record.ct_handshake) {
1268                                 break;
1269                             } else {
1270                                 hmFrag = (HandshakeFragment)rFrag;
1271                             }
1272                         }
1273                     } while (!bufferedFragments.isEmpty() &&
1274                             (msgSeq == hmFrag.messageSeq));
1275 
1276                     // handshake hashing
1277                     handshakeHashing(hsFrag, plaintext);
1278 
1279                     this.nextRecordSeq = maxRecodeSN + 1;
1280 
1281                     return plaintext;
1282                 }
1283             }
1284         }
1285 
1286         boolean flightIsReady() {
1287 
1288             byte flightType = handshakeFlight.handshakeType;
1289             if (flightType == HandshakeFlight.HF_UNKNOWN) {
1290                 //
1291                 // the ChangeCipherSpec/Finished flight
1292                 //
1293                 if (expectCCSFlight) {
1294                     // Have the ChangeCipherSpec/Finished flight been received?
1295                     boolean isReady = hasFinishedMessage(bufferedFragments);
1296                     if (debug != null && Debug.isOn("verbose")) {
1297                         Debug.log(
1298                             "Has the final flight been received? " + isReady);
1299                     }
1300 
1301                     return isReady;
1302                 }
1303 
1304                 if (debug != null && Debug.isOn("verbose")) {
1305                     Debug.log("No flight is received yet.");
1306                 }
1307 
1308                 return false;
1309             }
1310 
1311             if ((flightType == HandshakeMessage.ht_client_hello) ||
1312                 (flightType == HandshakeMessage.ht_hello_request) ||
1313                 (flightType == HandshakeMessage.ht_hello_verify_request)) {
1314 
1315                 // single handshake message flight
1316                 boolean isReady = hasCompleted(flightType);
1317                 if (debug != null && Debug.isOn("verbose")) {
1318                     Debug.log("Is the handshake message completed? " + isReady);

1319                 }
1320 
1321                 return isReady;
1322             }
1323 
1324             //
1325             // the ServerHello flight
1326             //
1327             if (flightType == HandshakeMessage.ht_server_hello) {
1328                 // Firstly, check the first flight handshake message.
1329                 if (!hasCompleted(flightType)) {
1330                     if (debug != null && Debug.isOn("verbose")) {
1331                         Debug.log(
1332                             "The ServerHello message is not completed yet.");
1333                     }
1334 
1335                     return false;
1336                 }
1337 
1338                 //
1339                 // an abbreviated handshake
1340                 //
1341                 if (hasFinishedMessage(bufferedFragments)) {
1342                     if (debug != null && Debug.isOn("verbose")) {
1343                         Debug.log("It's an abbreviated handshake.");
1344                     }
1345 
1346                     return true;
1347                 }
1348 
1349                 //
1350                 // a full handshake
1351                 //
1352                 List<HoleDescriptor> holes = handshakeFlight.holesMap.get(
1353                         HandshakeMessage.ht_server_hello_done);
1354                 if ((holes == null) || !holes.isEmpty()) {
1355                     // Not yet got the final message of the flight.
1356                     if (debug != null && Debug.isOn("verbose")) {
1357                         Debug.log("Not yet got the ServerHelloDone message");

1358                     }
1359 
1360                     return false;
1361                 }
1362 
1363                 // Have all handshake message been received?
1364                 boolean isReady = hasCompleted(bufferedFragments,
1365                             handshakeFlight.minMessageSeq,
1366                             handshakeFlight.maxMessageSeq);
1367                 if (debug != null && Debug.isOn("verbose")) {
1368                     Debug.log("Is the ServerHello flight (message " +

1369                             handshakeFlight.minMessageSeq + "-" +
1370                             handshakeFlight.maxMessageSeq +
1371                             ") completed? " + isReady);
1372                 }
1373 
1374                 return isReady;
1375             }
1376 
1377             //
1378             // the ClientKeyExchange flight
1379             //
1380             // Note: need to consider more messages in this flight if
1381             //       ht_supplemental_data and ht_certificate_url are
1382             //       suppported in the future.
1383             //
1384             if ((flightType == HandshakeMessage.ht_certificate) ||
1385                 (flightType == HandshakeMessage.ht_client_key_exchange)) {
1386 
1387                 // Firstly, check the first flight handshake message.
1388                 if (!hasCompleted(flightType)) {
1389                     if (debug != null && Debug.isOn("verbose")) {
1390                         Debug.log(
1391                             "The ClientKeyExchange or client Certificate " +
1392                             "message is not completed yet.");
1393                     }
1394 
1395                     return false;
1396                 }
1397 
1398                 // Is client CertificateVerify a mandatory message?
1399                 if (flightType == HandshakeMessage.ht_certificate) {
1400                     if (needClientVerify(bufferedFragments) &&
1401                         !hasCompleted(ht_certificate_verify)) {
1402 
1403                         if (debug != null && Debug.isOn("verbose")) {
1404                             Debug.log(
1405                                 "Not yet have the CertificateVerify message");
1406                         }
1407 
1408                         return false;
1409                     }
1410                 }
1411 
1412                 if (!hasFinishedMessage(bufferedFragments)) {
1413                     // not yet have the ChangeCipherSpec/Finished messages
1414                     if (debug != null && Debug.isOn("verbose")) {
1415                         Debug.log(
1416                             "Not yet have the ChangeCipherSpec and " +
1417                             "Finished messages");
1418                     }
1419 
1420                     return false;
1421                 }
1422 
1423                 // Have all handshake message been received?
1424                 boolean isReady = hasCompleted(bufferedFragments,
1425                             handshakeFlight.minMessageSeq,
1426                             handshakeFlight.maxMessageSeq);
1427                 if (debug != null && Debug.isOn("verbose")) {
1428                     Debug.log("Is the ClientKeyExchange flight (message " +

1429                             handshakeFlight.minMessageSeq + "-" +
1430                             handshakeFlight.maxMessageSeq +
1431                             ") completed? " + isReady);
1432                 }
1433 
1434                 return isReady;
1435             }
1436 
1437             //
1438             // Otherwise, need to receive more handshake messages.
1439             //
1440             if (debug != null && Debug.isOn("verbose")) {
1441                 Debug.log("Need to receive more handshake messages");
1442             }
1443 
1444             return false;
1445         }
1446 
1447         // Looking for the ChangeCipherSpec and Finished messages.
1448         //
1449         // As the cached Finished message should be a ciphertext, we don't
1450         // exactly know a ciphertext is a Finished message or not.  According
1451         // to the spec of TLS/DTLS handshaking, a Finished message is always
1452         // sent immediately after a ChangeCipherSpec message.  The first
1453         // ciphertext handshake message should be the expected Finished message.
1454         private boolean hasFinishedMessage(Set<RecordFragment> fragments) {
1455 
1456             boolean hasCCS = false;
1457             boolean hasFin = false;
1458             for (RecordFragment fragment : fragments) {
1459                 if (fragment.contentType == Record.ct_change_cipher_spec) {
1460                     if (hasFin) {
1461                         return true;
1462                     }
1463                     hasCCS = true;
1464                 } else if (fragment.contentType == Record.ct_handshake) {
1465                     // Finished is the first expected message of a new epoch.
1466                     if (fragment.isCiphertext) {
1467                         if (hasCCS) {
1468                             return true;
1469                         }
1470                         hasFin = true;
1471                     }
1472                 }
1473             }
1474 
1475             return hasFin && hasCCS;
1476         }
1477 
1478         // Is client CertificateVerify a mandatory message?
1479         //
1480         // In the current implementation, client CertificateVerify is a
1481         // mandatory message if the client Certificate is not empty.
1482         private boolean needClientVerify(Set<RecordFragment> fragments) {
1483 
1484             // The caller should have checked the completion of the first
1485             // present handshake message.  Need not to check it again.
1486             for (RecordFragment rFrag : fragments) {
1487                 if ((rFrag.contentType != Record.ct_handshake) ||
1488                         rFrag.isCiphertext) {
1489                     break;
1490                 }
1491 
1492                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
1493                 if (hsFrag.handshakeType != HandshakeMessage.ht_certificate) {
1494                     continue;
1495                 }
1496 
1497                 return (rFrag.fragment != null) &&
1498                    (rFrag.fragment.length > DTLSRecord.minCertPlaintextSize);
1499             }
1500 
1501             return false;
1502         }
1503 
1504         private boolean hasCompleted(byte handshakeType) {
1505             List<HoleDescriptor> holes =
1506                     handshakeFlight.holesMap.get(handshakeType);
1507             if (holes == null) {
1508                 // not yet received this kind of handshake message
1509                 return false;
1510             }
1511 
1512             return holes.isEmpty();  // no fragment hole for complete message
1513         }
1514 
1515         private boolean hasCompleted(
1516                 Set<RecordFragment> fragments,
1517                 int presentMsgSeq, int endMsgSeq) {
1518 
1519             // The caller should have checked the completion of the first
1520             // present handshake message.  Need not to check it again.
1521             for (RecordFragment rFrag : fragments) {
1522                 if ((rFrag.contentType != Record.ct_handshake) ||
1523                         rFrag.isCiphertext) {
1524                     break;
1525                 }
1526 
1527                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
1528                 if (hsFrag.messageSeq == presentMsgSeq) {
1529                     continue;
1530                 } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) {
1531                     // check the completion of the handshake message
1532                     if (!hasCompleted(hsFrag.handshakeType)) {
1533                         return false;
1534                     }
1535 
1536                     presentMsgSeq = hsFrag.messageSeq;
1537                 } else {
1538                     // not yet got handshake message next to presentMsgSeq
1539                     break;
1540                 }
1541             }
1542 
1543             return (presentMsgSeq >= endMsgSeq);
1544                         // false: if not yet got all messages of the flight.
1545         }
1546 
1547         private void handshakeHashing(
1548                 HandshakeFragment hsFrag, Plaintext plaintext) {
1549 
1550             byte hsType = hsFrag.handshakeType;
1551             if ((hsType == HandshakeMessage.ht_hello_request) ||
1552                 (hsType == HandshakeMessage.ht_hello_verify_request)) {
1553 
1554                 // omitted from handshake hash computation
1555                 return;
1556             }
1557 
1558             if ((hsFrag.messageSeq == 0) &&
1559                 (hsType == HandshakeMessage.ht_client_hello)) {
1560 
1561                 // omit initial ClientHello message
1562                 //
1563                 //  4: handshake header
1564                 //  2: ClientHello.client_version
1565                 // 32: ClientHello.random
1566                 int sidLen = plaintext.fragment.get(38);
1567 
1568                 if (sidLen == 0) {      // empty session_id, initial handshake
1569                     return;
1570                 }
1571             }
1572 
1573             // calculate the DTLS header
1574             byte[] temporary = new byte[12];    // 12: handshake header size
1575 
1576             // Handshake.msg_type
1577             temporary[0] = hsFrag.handshakeType;
1578 
1579             // Handshake.length
1580             temporary[1] = (byte)((hsFrag.messageLength >> 16) & 0xFF);
1581             temporary[2] = (byte)((hsFrag.messageLength >> 8) & 0xFF);
1582             temporary[3] = (byte)(hsFrag.messageLength & 0xFF);
1583 
1584             // Handshake.message_seq
1585             temporary[4] = (byte)((hsFrag.messageSeq >> 8) & 0xFF);
1586             temporary[5] = (byte)(hsFrag.messageSeq & 0xFF);
1587 
1588             // Handshake.fragment_offset
1589             temporary[6] = 0;
1590             temporary[7] = 0;
1591             temporary[8] = 0;
1592 
1593             // Handshake.fragment_length
1594             temporary[9] = temporary[1];
1595             temporary[10] = temporary[2];
1596             temporary[11] = temporary[3];
1597 
1598             plaintext.fragment.position(4);     // ignore the TLS header
1599             if ((hsType != HandshakeMessage.ht_finished) &&
1600                 (hsType != HandshakeMessage.ht_certificate_verify)) {
1601 
1602                 if (handshakeHash == null) {
1603                     // used for cache only
1604                     handshakeHash = new HandshakeHash(false);
1605                 }
1606                 handshakeHash.update(temporary, 0, 12);
1607                 handshakeHash.update(plaintext.fragment);
1608             } else {
1609                 // Reserve until this handshake message has been processed.
1610                 if (handshakeHash == null) {
1611                     // used for cache only
1612                     handshakeHash = new HandshakeHash(false);
1613                 }
1614                 handshakeHash.reserve(temporary, 0, 12);
1615                 handshakeHash.reserve(plaintext.fragment);
1616             }
1617             plaintext.fragment.position(0);     // restore the position
1618         }
1619     }
1620 }
1621 
   1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 9406+5 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.*;
  29 import java.nio.*;
  30 import java.security.GeneralSecurityException;
  31 import java.util.*;
  32 import javax.crypto.BadPaddingException;

  33 import javax.net.ssl.*;
  34 import sun.security.ssl.SSLCipher.SSLReadCipher;


  35 
  36 /**
  37  * DTLS {@code InputRecord} implementation for {@code SSLEngine}.
  38  */
  39 final class DTLSInputRecord extends InputRecord implements DTLSRecord {

  40     private DTLSReassembler reassembler = null;
  41     private int             readEpoch;
  42 
  43     DTLSInputRecord(HandshakeHash handshakeHash) {
  44         super(handshakeHash, SSLReadCipher.nullDTlsReadCipher());





  45         this.readEpoch = 0;





  46     }
  47 
  48     @Override
  49     void changeReadCiphers(SSLReadCipher readCipher) {









  50         this.readCipher = readCipher;
  51         this.readEpoch++;
  52     }
  53 
  54     @Override
  55     public synchronized void close() throws IOException {
  56         if (!isClosed) {

  57             super.close();
  58         }
  59     }
  60 
  61     @Override
  62     boolean isEmpty() {
  63         return ((reassembler == null) || reassembler.isEmpty());
  64     }
  65 
  66     @Override
  67     int estimateFragmentSize(int packetSize) {





  68         if (packetSize > 0) {
  69             return readCipher.estimateFragmentSize(packetSize, headerSize);

  70         } else {
  71             return Record.maxDataSize;
  72         }
  73     }
  74 
  75     @Override
  76     void expectingFinishFlight() {
  77         if (reassembler != null) {
  78             reassembler.expectingFinishFlight();
  79         }
  80     }
  81 
  82     @Override
  83     void finishHandshake() {
  84         reassembler = null;
  85     }
  86 
  87     @Override
  88     Plaintext acquirePlaintext() {
  89         if (reassembler != null) {
  90             return reassembler.acquirePlaintext();
  91         }
  92 
  93         return null;
  94     }
  95 
  96      @Override
  97     Plaintext[] decode(ByteBuffer[] srcs, int srcsOffset,
  98             int srcsLength) throws IOException, BadPaddingException {
  99         if (srcs == null || srcs.length == 0 || srcsLength == 0) {
 100             Plaintext pt = acquirePlaintext();
 101             return pt == null ? new Plaintext[0] : new Plaintext[] { pt };
 102         } else if (srcsLength == 1) {
 103             return decode(srcs[srcsOffset]);
 104         } else {
 105             ByteBuffer packet = extract(srcs,
 106                     srcsOffset, srcsLength, DTLSRecord.headerSize);
 107             return decode(packet);
 108         }
 109     }
 110 
 111     Plaintext[] decode(ByteBuffer packet) {
 112         if (isClosed) {
 113             return null;
 114         }
 115 
 116         if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
 117             SSLLogger.fine("Raw read", packet);

 118         }
 119 
 120         // The caller should have validated the record.
 121         int srcPos = packet.position();
 122         int srcLim = packet.limit();
 123 
 124         byte contentType = packet.get();                   // pos: 0
 125         byte majorVersion = packet.get();                  // pos: 1
 126         byte minorVersion = packet.get();                  // pos: 2
 127         byte[] recordEnS = new byte[8];                    // epoch + seqence
 128         packet.get(recordEnS);
 129         int recordEpoch = ((recordEnS[0] & 0xFF) << 8) |
 130                            (recordEnS[1] & 0xFF);          // pos: 3, 4
 131         long recordSeq  = ((recordEnS[2] & 0xFFL) << 40) |
 132                           ((recordEnS[3] & 0xFFL) << 32) |
 133                           ((recordEnS[4] & 0xFFL) << 24) |
 134                           ((recordEnS[5] & 0xFFL) << 16) |
 135                           ((recordEnS[6] & 0xFFL) <<  8) |
 136                            (recordEnS[7] & 0xFFL);         // pos: 5-10
 137 
 138         int contentLen = ((packet.get() & 0xFF) << 8) |
 139                           (packet.get() & 0xFF);           // pos: 11, 12
 140 
 141         if (SSLLogger.isOn && SSLLogger.isOn("record")) {
 142             SSLLogger.fine("READ: " +
 143                     ProtocolVersion.nameOf(majorVersion, minorVersion) +
 144                     " " + ContentType.nameOf(contentType) + ", length = " +
 145                     contentLen);
 146         }
 147 
 148         int recLim = srcPos + DTLSRecord.headerSize + contentLen;
 149 
 150         if (this.readEpoch > recordEpoch) {
 151             // Reset the position of the packet buffer.
 152             packet.position(recLim);
 153             if (SSLLogger.isOn && SSLLogger.isOn("record")) {
 154                 SSLLogger.fine("READ: discard this old record", recordEnS);
 155             }
 156             return null;
 157         }
 158 
 159         // Buffer next epoch message if necessary.
 160         if (this.readEpoch < recordEpoch) {
 161             // Discard the record younger than the current epcoh if:
 162             // 1. it is not a handshake message, or
 163             // 3. it is not of next epoch.
 164             if ((contentType != ContentType.HANDSHAKE.id &&
 165                     contentType != ContentType.CHANGE_CIPHER_SPEC.id) ||
 166                 (reassembler == null &&
 167                     contentType != ContentType.HANDSHAKE.id) ||
 168                 (this.readEpoch < (recordEpoch - 1))) {
 169 
 170                 packet.position(recLim);
 171 
 172                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 173                     SSLLogger.fine("Premature record (epoch), discard it.");
 174                 }
 175 
 176                 return null;
 177             }
 178 
 179 
 180             // Not ready to decrypt this record, may be an encrypted Finished
 181             // message, need to buffer it.
 182             byte[] fragment = new byte[contentLen];
 183             packet.get(fragment);              // copy the fragment
 184             RecordFragment buffered = new RecordFragment(fragment, contentType,
 185                     majorVersion, minorVersion,
 186                     recordEnS, recordEpoch, recordSeq, true);
 187 
 188             if (reassembler == null) {
 189                 reassembler = new DTLSReassembler(recordEpoch);
 190             }
 191             reassembler.queueUpFragment(buffered);
 192 
 193             // consume the full record in the packet buffer.
 194             packet.position(recLim);
 195 
 196             Plaintext pt = reassembler.acquirePlaintext();
 197             return pt == null ? null : new Plaintext[] { pt };
 198         }
 199 
 200         //
 201         // Now, the message is of this epoch.
 202         //










 203         // decrypt the fragment
 204         packet.limit(recLim);
 205         packet.position(srcPos + DTLSRecord.headerSize);
 206 
 207         ByteBuffer plaintextFragment;
 208         try {
 209             Plaintext plaintext =
 210                     readCipher.decrypt(contentType, packet, recordEnS);
 211             plaintextFragment = plaintext.fragment;
 212             contentType = plaintext.contentType;
 213         } catch (GeneralSecurityException gse) {
 214             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 215                 SSLLogger.fine("Discard invalid record: " + gse);
 216             }
 217 
 218             // invalid, discard this record [section 4.1.2.7, RFC 6347]
 219             return null;
 220         } finally {
 221             // comsume a complete record
 222             packet.limit(srcLim);
 223             packet.position(recLim);
 224         }
 225 
 226         if (contentType != ContentType.CHANGE_CIPHER_SPEC.id &&
 227             contentType != ContentType.HANDSHAKE.id) {   // app data or alert
 228                                                     // no retransmission
 229             // Cleanup the handshake reassembler if necessary.
 230             if ((reassembler != null) &&
 231                     (reassembler.handshakeEpoch < recordEpoch)) {
 232                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 233                     SSLLogger.fine("Cleanup the handshake reassembler");
 234                 }
 235 
 236                 reassembler = null;
 237             }
 238 
 239             return new Plaintext[] {
 240                     new Plaintext(contentType, majorVersion, minorVersion,
 241                             recordEpoch, Authenticator.toLong(recordEnS),
 242                             plaintextFragment)};
 243         }
 244 
 245         if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
 246             if (reassembler == null) {












 247                 reassembler = new DTLSReassembler(recordEpoch);
 248             }
 249 
 250             reassembler.queueUpChangeCipherSpec(
 251                     new RecordFragment(plaintextFragment, contentType,
 252                             majorVersion, minorVersion,
 253                             recordEnS, recordEpoch, recordSeq, false));
 254         } else {    // handshake record
 255             // One record may contain 1+ more handshake messages.
 256             while (plaintextFragment.remaining() > 0) {
 257 
 258                 HandshakeFragment hsFrag = parseHandshakeMessage(
 259                     contentType, majorVersion, minorVersion,
 260                     recordEnS, recordEpoch, recordSeq, plaintextFragment);
 261 
 262                 if (hsFrag == null) {
 263                     // invalid, discard this record
 264                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 265                         SSLLogger.fine(
 266                                 "Invalid handshake message, discard it.");
 267                     }
 268 
 269                     return null;
 270                 }
 271 
 272                 if (reassembler == null) {












 273                     reassembler = new DTLSReassembler(recordEpoch);
 274                 }
 275 
 276                 reassembler.queueUpHandshake(hsFrag);
 277             }
 278         }
 279 
 280         // Completed the read of the full record.  Acquire the reassembled
 281         // messages.
 282         if (reassembler != null) {
 283             Plaintext pt = reassembler.acquirePlaintext();
 284             return pt == null ? null : new Plaintext[] { pt };
 285         }
 286 
 287         if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 288              SSLLogger.fine("The reassembler is not initialized yet.");
 289         }
 290 
 291         return null;
 292     }
 293 
 294     @Override
 295     int bytesInCompletePacket(
 296         ByteBuffer[] srcs, int srcsOffset, int srcsLength) throws IOException {
 297 
 298         return bytesInCompletePacket(srcs[srcsOffset]);
 299     }
 300 
 301     private int bytesInCompletePacket(ByteBuffer packet) throws SSLException {
 302 
 303         // DTLS length field is in bytes 11/12
 304         if (packet.remaining() < headerSize) {
 305             return -1;
 306         }
 307 
 308         // Last sanity check that it's not a wild record
 309         int pos = packet.position();
 310 
 311         // Check the content type of the record.
 312         byte contentType = packet.get(pos);
 313         if (ContentType.valueOf(contentType) == null) {
 314             throw new SSLException(
 315                     "Unrecognized SSL message, plaintext connection?");
 316         }
 317 
 318         // Check the protocol version of the record.
 319         byte majorVersion = packet.get(pos + 1);
 320         byte minorVersion = packet.get(pos + 2);
 321         if (!ProtocolVersion.isNegotiable(
 322                 majorVersion, minorVersion, true, false)) {
 323             throw new SSLException("Unrecognized record version " +
 324                     ProtocolVersion.nameOf(majorVersion, minorVersion) +
 325                     " , plaintext connection?");
 326         }
 327 
 328         // Get the fragment length of the record.
 329         int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) +
 330                        (packet.get(pos + 12) & 0xFF) + headerSize;
 331         if (fragLen > Record.maxFragmentSize) {
 332             throw new SSLException(
 333                     "Record overflow, fragment length (" + fragLen +
 334                     ") MUST not exceed " + Record.maxFragmentSize);
 335         }
 336 
 337         return fragLen;
 338     }
 339 











 340     private static HandshakeFragment parseHandshakeMessage(
 341             byte contentType, byte majorVersion, byte minorVersion,
 342             byte[] recordEnS, int recordEpoch, long recordSeq,
 343             ByteBuffer plaintextFragment) {
 344 
 345         int remaining = plaintextFragment.remaining();
 346         if (remaining < handshakeHeaderSize) {
 347             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 348                 SSLLogger.fine("Discard invalid record: " +
 349                         "too small record to hold a handshake fragment");
 350             }
 351 
 352             // invalid, discard this record [section 4.1.2.7, RFC 6347]
 353             return null;
 354         }
 355 
 356         byte handshakeType = plaintextFragment.get();       // pos: 0
 357         int messageLength =
 358                 ((plaintextFragment.get() & 0xFF) << 16) |
 359                 ((plaintextFragment.get() & 0xFF) << 8) |
 360                  (plaintextFragment.get() & 0xFF);          // pos: 1-3
 361         int messageSeq =
 362                 ((plaintextFragment.get() & 0xFF) << 8) |
 363                  (plaintextFragment.get() & 0xFF);          // pos: 4/5
 364         int fragmentOffset =
 365                 ((plaintextFragment.get() & 0xFF) << 16) |
 366                 ((plaintextFragment.get() & 0xFF) << 8) |
 367                  (plaintextFragment.get() & 0xFF);          // pos: 6-8
 368         int fragmentLength =
 369                 ((plaintextFragment.get() & 0xFF) << 16) |
 370                 ((plaintextFragment.get() & 0xFF) << 8) |
 371                  (plaintextFragment.get() & 0xFF);          // pos: 9-11
 372         if ((remaining - handshakeHeaderSize) < fragmentLength) {
 373             if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 374                 SSLLogger.fine("Discard invalid record: " +
 375                         "not a complete handshake fragment in the record");
 376             }
 377 
 378             // invalid, discard this record [section 4.1.2.7, RFC 6347]
 379             return null;
 380         }
 381 
 382         byte[] fragment = new byte[fragmentLength];
 383         plaintextFragment.get(fragment);
 384 
 385         return new HandshakeFragment(fragment, contentType,
 386                 majorVersion, minorVersion,
 387                 recordEnS, recordEpoch, recordSeq,
 388                 handshakeType, messageLength,
 389                 messageSeq, fragmentOffset, fragmentLength);
 390     }
 391 
 392     // buffered record fragment
 393     private static class RecordFragment implements Comparable<RecordFragment> {
 394         boolean         isCiphertext;


 411             fragBuf.get(this.fragment);
 412         }
 413 
 414         RecordFragment(byte[] fragment, byte contentType,
 415                 byte majorVersion, byte minorVersion, byte[] recordEnS,
 416                 int recordEpoch, long recordSeq, boolean isCiphertext) {
 417             this.isCiphertext = isCiphertext;
 418 
 419             this.contentType = contentType;
 420             this.majorVersion = majorVersion;
 421             this.minorVersion = minorVersion;
 422             this.recordEpoch = recordEpoch;
 423             this.recordSeq = recordSeq;
 424             this.recordEnS = recordEnS;
 425             this.fragment = fragment;       // The caller should have cloned
 426                                             // the buffer if necessary.
 427         }
 428 
 429         @Override
 430         public int compareTo(RecordFragment o) {
 431             if (this.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
 432                 if (o.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
 433                     // Only one incoming ChangeCipherSpec message for an epoch.
 434                     //
 435                     // Ignore duplicated ChangeCipherSpec messages.
 436                     return Integer.compare(this.recordEpoch, o.recordEpoch);
 437                 } else if ((this.recordEpoch == o.recordEpoch) &&
 438                         (o.contentType == ContentType.HANDSHAKE.id)) {
 439                     // ChangeCipherSpec is the latest message of an epoch.
 440                     return 1;
 441                 }
 442             } else if (o.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
 443                 if ((this.recordEpoch == o.recordEpoch) &&
 444                         (this.contentType == ContentType.HANDSHAKE.id)) {
 445                     // ChangeCipherSpec is the latest message of an epoch.
 446                     return -1;
 447                 } else {
 448                     // different epoch or this is not a handshake message
 449                     return compareToSequence(o.recordEpoch, o.recordSeq);
 450                 }
 451             }
 452 
 453             return compareToSequence(o.recordEpoch, o.recordSeq);
 454         }
 455 
 456         int compareToSequence(int epoch, long seq) {
 457             if (this.recordEpoch > epoch) {
 458                 return 1;
 459             } else if (this.recordEpoch == epoch) {
 460                 return Long.compare(this.recordSeq, seq);
 461             } else {
 462                 return -1;
 463             }
 464         }


 489             this.fragmentLength = fragmentLength;
 490         }
 491 
 492         @Override
 493         public int compareTo(RecordFragment o) {
 494             if (o instanceof HandshakeFragment) {
 495                 HandshakeFragment other = (HandshakeFragment)o;
 496                 if (this.messageSeq != other.messageSeq) {
 497                     // keep the insertion order of handshake messages
 498                     return this.messageSeq - other.messageSeq;
 499                 } else if (this.fragmentOffset != other.fragmentOffset) {
 500                     // small fragment offset was transmitted first
 501                     return this.fragmentOffset - other.fragmentOffset;
 502                 } else if (this.fragmentLength == other.fragmentLength) {
 503                     // retransmissions, ignore duplicated messages.
 504                     return 0;
 505                 }
 506 
 507                 // Should be repacked for suitable fragment length.
 508                 //
 509                 // Note that the acquiring processes will reassemble the
 510                 // the fragments later.
 511                 return compareToSequence(o.recordEpoch, o.recordSeq);
 512             }
 513 
 514             return super.compareTo(o);
 515         }
 516     }
 517 
 518     private static final class HoleDescriptor {
 519         int offset;             // fragment_offset
 520         int limit;              // fragment_offset + fragment_length
 521 
 522         HoleDescriptor(int offset, int limit) {
 523             this.offset = offset;
 524             this.limit = limit;
 525         }
 526     }
 527 
 528     private static final class HandshakeFlight implements Cloneable {
 529         static final byte HF_UNKNOWN = SSLHandshake.NOT_APPLICABLE.id;
 530 
 531         byte        handshakeType;      // handshake type
 532         int         flightEpoch;        // the epoch of the first message
 533         int         minMessageSeq;      // minimal message sequence
 534 
 535         int         maxMessageSeq;      // maximum message sequence
 536         int         maxRecordEpoch;     // maximum record sequence number
 537         long        maxRecordSeq;       // maximum record sequence number
 538 
 539         HashMap<Byte, List<HoleDescriptor>> holesMap;
 540 
 541         HandshakeFlight() {
 542             this.handshakeType = HF_UNKNOWN;
 543             this.flightEpoch = 0;
 544             this.minMessageSeq = 0;
 545 
 546             this.maxMessageSeq = 0;
 547             this.maxRecordEpoch = 0;
 548             this.maxRecordSeq = -1;
 549 


 615             if (!isDesirable(hsf)) {
 616                 // Not a dedired record, discard it.
 617                 return;
 618             }
 619 
 620             // Clean up the retransmission messages if necessary.
 621             cleanUpRetransmit(hsf);
 622 
 623             // Is it the first message of next flight?
 624             //
 625             // Note: the Finished message is handled in the final CCS flight.
 626             boolean isMinimalFlightMessage = false;
 627             if (handshakeFlight.minMessageSeq == hsf.messageSeq) {
 628                 isMinimalFlightMessage = true;
 629             } else if ((precedingFlight != null) &&
 630                     (precedingFlight.minMessageSeq == hsf.messageSeq)) {
 631                 isMinimalFlightMessage = true;
 632             }
 633 
 634             if (isMinimalFlightMessage && (hsf.fragmentOffset == 0) &&
 635                     (hsf.handshakeType != SSLHandshake.FINISHED.id)) {
 636 
 637                 // reset the handshake flight
 638                 handshakeFlight.handshakeType = hsf.handshakeType;
 639                 handshakeFlight.flightEpoch = hsf.recordEpoch;
 640                 handshakeFlight.minMessageSeq = hsf.messageSeq;
 641             }
 642 
 643             if (hsf.handshakeType == SSLHandshake.FINISHED.id) {
 644                 handshakeFlight.maxMessageSeq = hsf.messageSeq;
 645                 handshakeFlight.maxRecordEpoch = hsf.recordEpoch;
 646                 handshakeFlight.maxRecordSeq = hsf.recordSeq;
 647             } else {
 648                 if (handshakeFlight.maxMessageSeq < hsf.messageSeq) {
 649                     handshakeFlight.maxMessageSeq = hsf.messageSeq;
 650                 }
 651 
 652                 int n = (hsf.recordEpoch - handshakeFlight.maxRecordEpoch);
 653                 if (n > 0) {
 654                     handshakeFlight.maxRecordEpoch = hsf.recordEpoch;
 655                     handshakeFlight.maxRecordSeq = hsf.recordSeq;
 656                 } else if (n == 0) {
 657                     // the same epoch
 658                     if (handshakeFlight.maxRecordSeq < hsf.recordSeq) {
 659                         handshakeFlight.maxRecordSeq = hsf.recordSeq;
 660                     }
 661                 }   // Otherwise, it is unlikely to happen.
 662             }
 663 


 668                 fragmented = true;
 669             }
 670 
 671             List<HoleDescriptor> holes =
 672                     handshakeFlight.holesMap.get(hsf.handshakeType);
 673             if (holes == null) {
 674                 if (!fragmented) {
 675                     holes = Collections.emptyList();
 676                 } else {
 677                     holes = new LinkedList<HoleDescriptor>();
 678                     holes.add(new HoleDescriptor(0, hsf.messageLength));
 679                 }
 680                 handshakeFlight.holesMap.put(hsf.handshakeType, holes);
 681             } else if (holes.isEmpty()) {
 682                 // Have got the full handshake message.  This record may be
 683                 // a handshake message retransmission.  Discard this record.
 684                 //
 685                 // It's OK to discard retransmission as the handshake hash
 686                 // is computed as if each handshake message had been sent
 687                 // as a single fragment.
 688                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 689                     SSLLogger.fine("Have got the full message, discard it.");
 690                 }
 691 
 692                 return;
 693             }
 694 
 695             if (fragmented) {
 696                 int fragmentLimit = hsf.fragmentOffset + hsf.fragmentLength;
 697                 for (int i = 0; i < holes.size(); i++) {
 698 
 699                     HoleDescriptor hole = holes.get(i);
 700                     if ((hole.limit <= hsf.fragmentOffset) ||
 701                         (hole.offset >= fragmentLimit)) {
 702                         // Also discard overlapping handshake retransmissions.
 703                         continue;
 704                     }
 705 
 706                     // The ranges SHOULD NOT overlap.
 707                     if (((hole.offset > hsf.fragmentOffset) &&
 708                          (hole.offset < fragmentLimit)) ||
 709                         ((hole.limit > hsf.fragmentOffset) &&
 710                          (hole.limit < fragmentLimit))) {
 711 
 712                         if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
 713                             SSLLogger.fine("Discard invalid record: " +
 714                                 "handshake fragment ranges are overlapping");
 715                         }
 716 
 717                         // invalid, discard it [section 4.1.2.7, RFC 6347]
 718                         return;
 719                     }
 720 
 721                     // This record interacts with this hole, fill the hole.
 722                     holes.remove(i);
 723                     // i--;
 724 
 725                     if (hsf.fragmentOffset > hole.offset) {
 726                         holes.add(new HoleDescriptor(
 727                                 hole.offset, hsf.fragmentOffset));
 728                         // i++;
 729                     }
 730 
 731                     if (fragmentLimit < hole.limit) {
 732                         holes.add(new HoleDescriptor(
 733                                 fragmentLimit, hole.limit));
 734                         // i++;
 735                     }
 736 
 737                     // As no ranges overlap, no interact with other holes.
 738                     break;
 739                 }
 740             }
 741 
 742             // buffer this fragment
 743             if (hsf.handshakeType == SSLHandshake.FINISHED.id) {
 744                 // Need no status update.
 745                 bufferedFragments.add(hsf);
 746             } else {
 747                 bufferFragment(hsf);
 748             }
 749         }
 750 
 751         // Queue up a ChangeCipherSpec message
 752         void queueUpChangeCipherSpec(RecordFragment rf) {
 753             if (!isDesirable(rf)) {
 754                 // Not a dedired record, discard it.
 755                 return;
 756             }
 757 
 758             // Clean up the retransmission messages if necessary.
 759             cleanUpRetransmit(rf);
 760 
 761             // Is it the first message of this flight?
 762             //
 763             // Note: the first message of the final flight is ChangeCipherSpec.


 799                 flightIsReady = false;
 800             }
 801 
 802             if (!needToCheckFlight) {
 803                 needToCheckFlight = true;
 804             }
 805         }
 806 
 807         private void cleanUpRetransmit(RecordFragment rf) {
 808             // Does the next flight start?
 809             boolean isNewFlight = false;
 810             if (precedingFlight != null) {
 811                 if (precedingFlight.flightEpoch < rf.recordEpoch) {
 812                     isNewFlight = true;
 813                 } else {
 814                     if (rf instanceof HandshakeFragment) {
 815                         HandshakeFragment hsf = (HandshakeFragment)rf;
 816                         if (precedingFlight.maxMessageSeq  < hsf.messageSeq) {
 817                             isNewFlight = true;
 818                         }
 819                     } else if (
 820                         rf.contentType != ContentType.CHANGE_CIPHER_SPEC.id) {
 821 
 822                         // ciphertext
 823                         if (precedingFlight.maxRecordEpoch < rf.recordEpoch) {
 824                             isNewFlight = true;
 825                         }
 826                     }
 827                 }
 828             }
 829 
 830             if (!isNewFlight) {
 831                 // Need no cleanup.
 832                 return;
 833             }
 834 
 835             // clean up the buffer
 836             for (Iterator<RecordFragment> it = bufferedFragments.iterator();
 837                     it.hasNext();) {
 838 
 839                 RecordFragment frag = it.next();
 840                 boolean isOld = false;
 841                 if (frag.recordEpoch < precedingFlight.maxRecordEpoch) {


 856                 } else {
 857                     // Safe to break as items in the buffer are ordered.
 858                     break;
 859                 }
 860             }
 861 
 862             // discard retransmissions of the previous flight if any.
 863             precedingFlight = null;
 864         }
 865 
 866         // Is a desired record?
 867         //
 868         // Check for retransmission and lost records.
 869         private boolean isDesirable(RecordFragment rf) {
 870             //
 871             // Discard records old than the previous epoch.
 872             //
 873             int previousEpoch = nextRecordEpoch - 1;
 874             if (rf.recordEpoch < previousEpoch) {
 875                 // Too old to use, discard this record.
 876                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 877                     SSLLogger.fine(
 878                             "Too old epoch to use this record, discard it.");
 879                 }
 880 
 881                 return false;
 882             }
 883 
 884             //
 885             // Allow retransmission of last flight of the previous epoch
 886             //
 887             // For example, the last server delivered flight for session
 888             // resuming abbreviated handshaking consist three messages:
 889             //      ServerHello
 890             //      [ChangeCipherSpec]
 891             //      Finished
 892             //
 893             // The epoch number is incremented and the sequence number is reset
 894             // if the ChangeCipherSpec is sent.
 895             if (rf.recordEpoch == previousEpoch) {
 896                 boolean isDesired = true;
 897                 if (precedingFlight == null) {
 898                     isDesired = false;
 899                 } else {
 900                     if (rf instanceof HandshakeFragment) {
 901                         HandshakeFragment hsf = (HandshakeFragment)rf;
 902                         if (precedingFlight.minMessageSeq > hsf.messageSeq) {
 903                             isDesired = false;
 904                         }
 905                     } else if (
 906                         rf.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
 907 
 908                         // ChangeCipherSpec
 909                         if (precedingFlight.flightEpoch != rf.recordEpoch) {
 910                             isDesired = false;
 911                         }
 912                     } else {        // ciphertext
 913                         if ((rf.recordEpoch < precedingFlight.maxRecordEpoch) ||
 914                             (rf.recordEpoch == precedingFlight.maxRecordEpoch &&
 915                                 rf.recordSeq <= precedingFlight.maxRecordSeq)) {
 916                             isDesired = false;
 917                         }
 918                     }
 919                 }
 920 
 921                 if (!isDesired) {
 922                     // Too old to use, discard this retransmitted record
 923                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 924                         SSLLogger.fine(
 925                                 "Too old retransmission to use, discard it.");
 926                     }
 927 
 928                     return false;
 929                 }
 930             } else if ((rf.recordEpoch == nextRecordEpoch) &&
 931                     (nextRecordSeq > rf.recordSeq)) {
 932 
 933                 // Previously disordered record for the current epoch.
 934                 //
 935                 // Should has been retransmitted. Discard this record.
 936                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 937                     SSLLogger.fine(
 938                             "Lagging behind record (sequence), discard it.");
 939                 }
 940 
 941                 return false;
 942             }
 943 
 944             return true;
 945         }
 946 
 947         private boolean isEmpty() {
 948             return (bufferedFragments.isEmpty() ||
 949                     (!flightIsReady && !needToCheckFlight) ||
 950                     (needToCheckFlight && !flightIsReady()));
 951         }
 952 
 953         Plaintext acquirePlaintext() {
 954             if (bufferedFragments.isEmpty()) {
 955                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 956                     SSLLogger.fine("No received handshake messages");
 957                 }
 958                 return null;
 959             }
 960 
 961             if (!flightIsReady && needToCheckFlight) {
 962                 // check the fligth status
 963                 flightIsReady = flightIsReady();
 964 
 965                 // Reset if this flight is ready.
 966                 if (flightIsReady) {
 967                     // Retransmitted handshake messages are not needed for
 968                     // further handshaking processing.
 969                     if (handshakeFlight.isRetransmitOf(precedingFlight)) {
 970                         // cleanup
 971                         bufferedFragments.clear();
 972 
 973                         // Reset the next handshake flight.
 974                         resetHandshakeFlight(precedingFlight);
 975 
 976                         if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 977                             SSLLogger.fine("Received a retransmission flight.");
 978                         }
 979 
 980                         return Plaintext.PLAINTEXT_NULL;
 981                     }
 982                 }
 983 
 984                 needToCheckFlight = false;
 985             }
 986 
 987             if (!flightIsReady) {
 988                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
 989                     SSLLogger.fine(
 990                             "The handshake flight is not ready to use: " +
 991                             handshakeFlight.handshakeType);
 992                 }
 993                 return null;
 994             }
 995 
 996             RecordFragment rFrag = bufferedFragments.first();
 997             Plaintext plaintext;
 998             if (!rFrag.isCiphertext) {
 999                 // handshake message, or ChangeCipherSpec message
1000                 plaintext = acquireHandshakeMessage();
1001 
1002                 // Reset the handshake flight.
1003                 if (bufferedFragments.isEmpty()) {
1004                     // Need not to backup the holes map.  Clear up it at first.
1005                     handshakeFlight.holesMap.clear();   // cleanup holes map
1006 
1007                     // Update the preceding flight.
1008                     precedingFlight = (HandshakeFlight)handshakeFlight.clone();
1009 
1010                     // Reset the next handshake flight.
1011                     resetHandshakeFlight(precedingFlight);
1012 
1013                     if (expectCCSFlight &&
1014                             (precedingFlight.handshakeType ==
1015                                     HandshakeFlight.HF_UNKNOWN)) {
1016                         expectCCSFlight = false;
1017                     }
1018                 }
1019             } else {
1020                 // a Finished message or other ciphertexts
1021                 plaintext = acquireCachedMessage();
1022             }
1023 
1024             return plaintext;
1025         }
1026 
1027         //
1028         // Reset the handshake flight from a previous one.
1029         //
1030         private void resetHandshakeFlight(HandshakeFlight prev) {
1031             // Reset the next handshake flight.
1032             handshakeFlight.handshakeType = HandshakeFlight.HF_UNKNOWN;
1033             handshakeFlight.flightEpoch = prev.maxRecordEpoch;
1034             if (prev.flightEpoch != prev.maxRecordEpoch) {


1046             //
1047             // Note: actually, we need to do nothing because the reassembler
1048             // of handshake messages will reset them properly even for
1049             // retransmissions.
1050             //
1051             handshakeFlight.maxMessageSeq = 0;
1052             handshakeFlight.maxRecordEpoch = handshakeFlight.flightEpoch;
1053 
1054             // Record sequence number cannot wrap even for retransmissions.
1055             handshakeFlight.maxRecordSeq = prev.maxRecordSeq + 1;
1056 
1057             // cleanup holes map
1058             handshakeFlight.holesMap.clear();
1059 
1060             // Ready to accept new input record.
1061             flightIsReady = false;
1062             needToCheckFlight = false;
1063         }
1064 
1065         private Plaintext acquireCachedMessage() {

1066             RecordFragment rFrag = bufferedFragments.first();
1067             if (readEpoch != rFrag.recordEpoch) {
1068                 if (readEpoch > rFrag.recordEpoch) {
1069                     // discard old records
1070                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1071                         SSLLogger.fine(
1072                                 "Discard old buffered ciphertext fragments.");
1073                     }
1074                     bufferedFragments.remove(rFrag);    // popup the fragment
1075                 }
1076 
1077                 // reset the flight
1078                 if (flightIsReady) {
1079                     flightIsReady = false;
1080                 }
1081 
1082                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1083                     SSLLogger.fine(
1084                             "Not yet ready to decrypt the cached fragments.");
1085                 }
1086                 return null;
1087             }
1088 
1089             bufferedFragments.remove(rFrag);    // popup the fragment
1090 
1091             ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment);
1092             ByteBuffer plaintextFragment = null;
1093             try {
1094                 Plaintext plaintext = readCipher.decrypt(
1095                         rFrag.contentType, fragment, rFrag.recordEnS);
1096                 plaintextFragment = plaintext.fragment;
1097                 rFrag.contentType = plaintext.contentType;
1098             } catch (GeneralSecurityException gse) {
1099                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1100                     SSLLogger.fine("Discard invalid record: ", gse);
1101                 }
1102 
1103                 // invalid, discard this record [section 4.1.2.7, RFC 6347]
1104                 return null;
1105             }
1106 
1107             // The ciphtext handshake message can only be Finished (the
1108             // end of this flight), ClinetHello or HelloRequest (the
1109             // beginning of the next flight) message.  Need not to check
1110             // any ChangeCipherSpec message.
1111             if (rFrag.contentType == ContentType.HANDSHAKE.id) {
1112                 while (plaintextFragment.remaining() > 0) {
1113                     HandshakeFragment hsFrag = parseHandshakeMessage(
1114                             rFrag.contentType,
1115                             rFrag.majorVersion, rFrag.minorVersion,
1116                             rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq,
1117                             plaintextFragment);
1118 
1119                     if (hsFrag == null) {
1120                         // invalid, discard this record
1121                         if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1122                             SSLLogger.fine(
1123                                     "Invalid handshake fragment, discard it",
1124                                     plaintextFragment);
1125                         }
1126                         return null;
1127                     }
1128 
1129                     queueUpHandshake(hsFrag);
1130                     // The flight ready status (flightIsReady) should have
1131                     // been checked and updated for the Finished handshake
1132                     // message before the decryption.  Please don't update
1133                     // flightIsReady for Finished messages.
1134                     if (hsFrag.handshakeType != SSLHandshake.FINISHED.id) {
1135                         flightIsReady = false;
1136                         needToCheckFlight = true;
1137                     }
1138                 }
1139 
1140                 return acquirePlaintext();
1141             } else {
1142                 return new Plaintext(rFrag.contentType,
1143                         rFrag.majorVersion, rFrag.minorVersion,
1144                         rFrag.recordEpoch,
1145                         Authenticator.toLong(rFrag.recordEnS),
1146                         plaintextFragment);
1147             }
1148         }
1149 
1150         private Plaintext acquireHandshakeMessage() {
1151 
1152             RecordFragment rFrag = bufferedFragments.first();
1153             if (rFrag.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
1154                 this.nextRecordEpoch = rFrag.recordEpoch + 1;
1155 
1156                 // For retransmissions, the next record sequence number is a
1157                 // positive value.  Don't worry about it as the acquiring of
1158                 // the immediately followed Finished handshake message will
1159                 // reset the next record sequence number correctly.
1160                 this.nextRecordSeq = 0;
1161 
1162                 // Popup the fragment.
1163                 bufferedFragments.remove(rFrag);




1164                 return new Plaintext(rFrag.contentType,
1165                         rFrag.majorVersion, rFrag.minorVersion,
1166                         rFrag.recordEpoch,
1167                         Authenticator.toLong(rFrag.recordEnS),
1168                         ByteBuffer.wrap(rFrag.fragment));
1169             } else {    // rFrag.contentType == ContentType.HANDSHAKE.id
1170                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
1171                 if ((hsFrag.messageLength == hsFrag.fragmentLength) &&
1172                     (hsFrag.fragmentOffset == 0)) {     // no fragmentation
1173 
1174                     bufferedFragments.remove(rFrag);    // popup the fragment
1175 
1176                     // this.nextRecordEpoch = hsFrag.recordEpoch;
1177                     this.nextRecordSeq = hsFrag.recordSeq + 1;
1178 
1179                     // Note: may try to avoid byte array copy in the future.
1180                     byte[] recordFrag = new byte[hsFrag.messageLength + 4];
1181                     Plaintext plaintext = new Plaintext(
1182                             hsFrag.contentType,
1183                             hsFrag.majorVersion, hsFrag.minorVersion,
1184                             hsFrag.recordEpoch,
1185                             Authenticator.toLong(hsFrag.recordEnS),
1186                             ByteBuffer.wrap(recordFrag));
1187 
1188                     // fill the handshake fragment of the record
1189                     recordFrag[0] = hsFrag.handshakeType;
1190                     recordFrag[1] =
1191                             (byte)((hsFrag.messageLength >>> 16) & 0xFF);
1192                     recordFrag[2] =
1193                             (byte)((hsFrag.messageLength >>> 8) & 0xFF);
1194                     recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
1195 
1196                     System.arraycopy(hsFrag.fragment, 0,
1197                             recordFrag, 4, hsFrag.fragmentLength);
1198 
1199                     // handshake hashing
1200                     handshakeHashing(hsFrag, plaintext);
1201 
1202                     return plaintext;
1203                 } else {                // fragmented handshake message
1204                     // the first record
1205                     //
1206                     // Note: may try to avoid byte array copy in the future.
1207                     byte[] recordFrag = new byte[hsFrag.messageLength + 4];
1208                     Plaintext plaintext = new Plaintext(
1209                             hsFrag.contentType,
1210                             hsFrag.majorVersion, hsFrag.minorVersion,
1211                             hsFrag.recordEpoch,
1212                             Authenticator.toLong(hsFrag.recordEnS),
1213                             ByteBuffer.wrap(recordFrag));
1214 
1215                     // fill the handshake fragment of the record
1216                     recordFrag[0] = hsFrag.handshakeType;
1217                     recordFrag[1] =
1218                             (byte)((hsFrag.messageLength >>> 16) & 0xFF);
1219                     recordFrag[2] =
1220                             (byte)((hsFrag.messageLength >>> 8) & 0xFF);
1221                     recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
1222 
1223                     int msgSeq = hsFrag.messageSeq;
1224                     long maxRecodeSN = hsFrag.recordSeq;
1225                     HandshakeFragment hmFrag = hsFrag;
1226                     do {
1227                         System.arraycopy(hmFrag.fragment, 0,
1228                                 recordFrag, hmFrag.fragmentOffset + 4,
1229                                 hmFrag.fragmentLength);
1230                         // popup the fragment
1231                         bufferedFragments.remove(rFrag);
1232 
1233                         if (maxRecodeSN < hmFrag.recordSeq) {
1234                             maxRecodeSN = hmFrag.recordSeq;
1235                         }
1236 
1237                         // Note: may buffer retransmitted fragments in order to
1238                         // speed up the reassembly in the future.
1239 
1240                         // read the next buffered record
1241                         if (!bufferedFragments.isEmpty()) {
1242                             rFrag = bufferedFragments.first();
1243                             if (rFrag.contentType != ContentType.HANDSHAKE.id) {
1244                                 break;
1245                             } else {
1246                                 hmFrag = (HandshakeFragment)rFrag;
1247                             }
1248                         }
1249                     } while (!bufferedFragments.isEmpty() &&
1250                             (msgSeq == hmFrag.messageSeq));
1251 
1252                     // handshake hashing
1253                     handshakeHashing(hsFrag, plaintext);
1254 
1255                     this.nextRecordSeq = maxRecodeSN + 1;
1256 
1257                     return plaintext;
1258                 }
1259             }
1260         }
1261 
1262         boolean flightIsReady() {
1263 
1264             byte flightType = handshakeFlight.handshakeType;
1265             if (flightType == HandshakeFlight.HF_UNKNOWN) {
1266                 //
1267                 // the ChangeCipherSpec/Finished flight
1268                 //
1269                 if (expectCCSFlight) {
1270                     // Have the ChangeCipherSpec/Finished flight been received?
1271                     boolean isReady = hasFinishedMessage(bufferedFragments);
1272                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1273                         SSLLogger.fine(
1274                             "Has the final flight been received? " + isReady);
1275                     }
1276 
1277                     return isReady;
1278                 }
1279 
1280                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1281                     SSLLogger.fine("No flight is received yet.");
1282                 }
1283 
1284                 return false;
1285             }
1286 
1287             if ((flightType == SSLHandshake.CLIENT_HELLO.id) ||
1288                 (flightType == SSLHandshake.HELLO_REQUEST.id) ||
1289                 (flightType == SSLHandshake.HELLO_VERIFY_REQUEST.id)) {
1290 
1291                 // single handshake message flight
1292                 boolean isReady = hasCompleted(flightType);
1293                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1294                     SSLLogger.fine(
1295                             "Is the handshake message completed? " + isReady);
1296                 }
1297 
1298                 return isReady;
1299             }
1300 
1301             //
1302             // the ServerHello flight
1303             //
1304             if (flightType == SSLHandshake.SERVER_HELLO.id) {
1305                 // Firstly, check the first flight handshake message.
1306                 if (!hasCompleted(flightType)) {
1307                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1308                         SSLLogger.fine(
1309                             "The ServerHello message is not completed yet.");
1310                     }
1311 
1312                     return false;
1313                 }
1314 
1315                 //
1316                 // an abbreviated handshake
1317                 //
1318                 if (hasFinishedMessage(bufferedFragments)) {
1319                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1320                         SSLLogger.fine("It's an abbreviated handshake.");
1321                     }
1322 
1323                     return true;
1324                 }
1325 
1326                 //
1327                 // a full handshake
1328                 //
1329                 List<HoleDescriptor> holes = handshakeFlight.holesMap.get(
1330                         SSLHandshake.SERVER_HELLO_DONE.id);
1331                 if ((holes == null) || !holes.isEmpty()) {
1332                     // Not yet got the final message of the flight.
1333                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1334                         SSLLogger.fine(
1335                                 "Not yet got the ServerHelloDone message");
1336                     }
1337 
1338                     return false;
1339                 }
1340 
1341                 // Have all handshake message been received?
1342                 boolean isReady = hasCompleted(bufferedFragments,
1343                             handshakeFlight.minMessageSeq,
1344                             handshakeFlight.maxMessageSeq);
1345                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1346                     SSLLogger.fine(
1347                             "Is the ServerHello flight (message " +
1348                             handshakeFlight.minMessageSeq + "-" +
1349                             handshakeFlight.maxMessageSeq +
1350                             ") completed? " + isReady);
1351                 }
1352 
1353                 return isReady;
1354             }
1355 
1356             //
1357             // the ClientKeyExchange flight
1358             //
1359             // Note: need to consider more messages in this flight if
1360             //       ht_supplemental_data and ht_certificate_url are
1361             //       suppported in the future.
1362             //
1363             if ((flightType == SSLHandshake.CERTIFICATE.id) ||
1364                 (flightType == SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
1365 
1366                 // Firstly, check the first flight handshake message.
1367                 if (!hasCompleted(flightType)) {
1368                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1369                         SSLLogger.fine(
1370                             "The ClientKeyExchange or client Certificate " +
1371                             "message is not completed yet.");
1372                     }
1373 
1374                     return false;
1375                 }
1376 
1377                 // Is client CertificateVerify a mandatory message?
1378                 if (flightType == SSLHandshake.CERTIFICATE.id) {
1379                     if (needClientVerify(bufferedFragments) &&
1380                         !hasCompleted(SSLHandshake.CERTIFICATE_VERIFY.id)) {
1381 
1382                         if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1383                             SSLLogger.fine(
1384                                 "Not yet have the CertificateVerify message");
1385                         }
1386 
1387                         return false;
1388                     }
1389                 }
1390 
1391                 if (!hasFinishedMessage(bufferedFragments)) {
1392                     // not yet have the ChangeCipherSpec/Finished messages
1393                     if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1394                         SSLLogger.fine(
1395                             "Not yet have the ChangeCipherSpec and " +
1396                             "Finished messages");
1397                     }
1398 
1399                     return false;
1400                 }
1401 
1402                 // Have all handshake message been received?
1403                 boolean isReady = hasCompleted(bufferedFragments,
1404                             handshakeFlight.minMessageSeq,
1405                             handshakeFlight.maxMessageSeq);
1406                 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1407                     SSLLogger.fine(
1408                             "Is the ClientKeyExchange flight (message " +
1409                             handshakeFlight.minMessageSeq + "-" +
1410                             handshakeFlight.maxMessageSeq +
1411                             ") completed? " + isReady);
1412                 }
1413 
1414                 return isReady;
1415             }
1416 
1417             //
1418             // Otherwise, need to receive more handshake messages.
1419             //
1420             if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
1421                 SSLLogger.fine("Need to receive more handshake messages");
1422             }
1423 
1424             return false;
1425         }
1426 
1427         // Looking for the ChangeCipherSpec and Finished messages.
1428         //
1429         // As the cached Finished message should be a ciphertext, we don't
1430         // exactly know a ciphertext is a Finished message or not.  According
1431         // to the spec of TLS/DTLS handshaking, a Finished message is always
1432         // sent immediately after a ChangeCipherSpec message.  The first
1433         // ciphertext handshake message should be the expected Finished message.
1434         private boolean hasFinishedMessage(Set<RecordFragment> fragments) {
1435 
1436             boolean hasCCS = false;
1437             boolean hasFin = false;
1438             for (RecordFragment fragment : fragments) {
1439                 if (fragment.contentType == ContentType.CHANGE_CIPHER_SPEC.id) {
1440                     if (hasFin) {
1441                         return true;
1442                     }
1443                     hasCCS = true;
1444                 } else if (fragment.contentType == ContentType.HANDSHAKE.id) {
1445                     // Finished is the first expected message of a new epoch.
1446                     if (fragment.isCiphertext) {
1447                         if (hasCCS) {
1448                             return true;
1449                         }
1450                         hasFin = true;
1451                     }
1452                 }
1453             }
1454 
1455             return hasFin && hasCCS;
1456         }
1457 
1458         // Is client CertificateVerify a mandatory message?
1459         //
1460         // In the current implementation, client CertificateVerify is a
1461         // mandatory message if the client Certificate is not empty.
1462         private boolean needClientVerify(Set<RecordFragment> fragments) {
1463 
1464             // The caller should have checked the completion of the first
1465             // present handshake message.  Need not to check it again.
1466             for (RecordFragment rFrag : fragments) {
1467                 if ((rFrag.contentType != ContentType.HANDSHAKE.id) ||
1468                         rFrag.isCiphertext) {
1469                     break;
1470                 }
1471 
1472                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
1473                 if (hsFrag.handshakeType != SSLHandshake.CERTIFICATE.id) {
1474                     continue;
1475                 }
1476 
1477                 return (rFrag.fragment != null) &&
1478                    (rFrag.fragment.length > DTLSRecord.minCertPlaintextSize);
1479             }
1480 
1481             return false;
1482         }
1483 
1484         private boolean hasCompleted(byte handshakeType) {
1485             List<HoleDescriptor> holes =
1486                     handshakeFlight.holesMap.get(handshakeType);
1487             if (holes == null) {
1488                 // not yet received this kind of handshake message
1489                 return false;
1490             }
1491 
1492             return holes.isEmpty();  // no fragment hole for complete message
1493         }
1494 
1495         private boolean hasCompleted(
1496                 Set<RecordFragment> fragments,
1497                 int presentMsgSeq, int endMsgSeq) {
1498 
1499             // The caller should have checked the completion of the first
1500             // present handshake message.  Need not to check it again.
1501             for (RecordFragment rFrag : fragments) {
1502                 if ((rFrag.contentType != ContentType.HANDSHAKE.id) ||
1503                         rFrag.isCiphertext) {
1504                     break;
1505                 }
1506 
1507                 HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
1508                 if (hsFrag.messageSeq == presentMsgSeq) {
1509                     continue;
1510                 } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) {
1511                     // check the completion of the handshake message
1512                     if (!hasCompleted(hsFrag.handshakeType)) {
1513                         return false;
1514                     }
1515 
1516                     presentMsgSeq = hsFrag.messageSeq;
1517                 } else {
1518                     // not yet got handshake message next to presentMsgSeq
1519                     break;
1520                 }
1521             }
1522 
1523             return (presentMsgSeq >= endMsgSeq);
1524                         // false: if not yet got all messages of the flight.
1525         }
1526 
1527         private void handshakeHashing(
1528                 HandshakeFragment hsFrag, Plaintext plaintext) {

1529             byte hsType = hsFrag.handshakeType;
1530             if (!handshakeHash.isHashable(hsType)) {


1531                 // omitted from handshake hash computation
1532                 return;
1533             }
1534 
1535             // calculate the DTLS header and reserve the handshake message
1536             plaintext.fragment.position(4);     // ignore the TLS header
1537             byte[] temporary = new byte[plaintext.fragment.remaining() + 12];
1538                                                 // 12: handshake header size













1539 
1540             // Handshake.msg_type
1541             temporary[0] = hsFrag.handshakeType;
1542 
1543             // Handshake.length
1544             temporary[1] = (byte)((hsFrag.messageLength >> 16) & 0xFF);
1545             temporary[2] = (byte)((hsFrag.messageLength >> 8) & 0xFF);
1546             temporary[3] = (byte)(hsFrag.messageLength & 0xFF);
1547 
1548             // Handshake.message_seq
1549             temporary[4] = (byte)((hsFrag.messageSeq >> 8) & 0xFF);
1550             temporary[5] = (byte)(hsFrag.messageSeq & 0xFF);
1551 
1552             // Handshake.fragment_offset
1553             temporary[6] = 0;
1554             temporary[7] = 0;
1555             temporary[8] = 0;
1556 
1557             // Handshake.fragment_length
1558             temporary[9] = temporary[1];
1559             temporary[10] = temporary[2];
1560             temporary[11] = temporary[3];
1561 
1562             plaintext.fragment.get(temporary,
1563                     12, plaintext.fragment.remaining());
1564             handshakeHash.receive(temporary);
















1565             plaintext.fragment.position(0);     // restore the position
1566         }
1567     }
1568 }
1569 
< prev index next >