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