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