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