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