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