16 * |
16 * |
17 * You should have received a copy of the GNU General Public License version |
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, |
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. |
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 * |
20 * |
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
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 |
22 * or visit www.oracle.com if you need additional information or have any |
23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package sun.security.ssl; |
26 package sun.security.ssl; |
27 |
27 |
28 import java.io.*; |
28 import java.io.IOException; |
29 import java.nio.*; |
29 import java.nio.ByteBuffer; |
30 import java.util.*; |
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; |
31 import javax.crypto.BadPaddingException; |
38 import javax.crypto.BadPaddingException; |
32 |
39 import javax.net.ssl.SSLException; |
33 import javax.net.ssl.*; |
40 import sun.security.ssl.SSLCipher.SSLReadCipher; |
34 |
|
35 import sun.security.util.HexDumpEncoder; |
|
36 import static sun.security.ssl.HandshakeMessage.*; |
|
37 |
41 |
38 /** |
42 /** |
39 * DTLS {@code InputRecord} implementation for {@code SSLEngine}. |
43 * DTLS {@code InputRecord} implementation for {@code SSLEngine}. |
40 */ |
44 */ |
41 final class DTLSInputRecord extends InputRecord implements DTLSRecord { |
45 final class DTLSInputRecord extends InputRecord implements DTLSRecord { |
42 |
|
43 private DTLSReassembler reassembler = null; |
46 private DTLSReassembler reassembler = null; |
44 |
47 private int readEpoch; |
45 int readEpoch; |
48 |
46 |
49 DTLSInputRecord(HandshakeHash handshakeHash) { |
47 int prevReadEpoch; |
50 super(handshakeHash, SSLReadCipher.nullDTlsReadCipher()); |
48 Authenticator prevReadAuthenticator; |
|
49 CipherBox prevReadCipher; |
|
50 |
|
51 DTLSInputRecord() { |
|
52 this.readEpoch = 0; |
51 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 } |
52 } |
59 |
53 |
60 @Override |
54 @Override |
61 void changeReadCiphers(Authenticator readAuthenticator, |
55 void changeReadCiphers(SSLReadCipher readCipher) { |
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; |
56 this.readCipher = readCipher; |
72 this.readEpoch++; |
57 this.readEpoch++; |
73 } |
58 } |
74 |
59 |
75 @Override |
60 @Override |
76 public synchronized void close() throws IOException { |
61 public synchronized void close() throws IOException { |
77 if (!isClosed) { |
62 if (!isClosed) { |
78 prevReadCipher.dispose(); |
|
79 super.close(); |
63 super.close(); |
80 } |
64 } |
81 } |
65 } |
82 |
66 |
83 @Override |
67 @Override |
147 (recordEnS[7] & 0xFFL); // pos: 5-10 |
142 (recordEnS[7] & 0xFFL); // pos: 5-10 |
148 |
143 |
149 int contentLen = ((packet.get() & 0xFF) << 8) | |
144 int contentLen = ((packet.get() & 0xFF) << 8) | |
150 (packet.get() & 0xFF); // pos: 11, 12 |
145 (packet.get() & 0xFF); // pos: 11, 12 |
151 |
146 |
152 if (debug != null && Debug.isOn("record")) { |
147 if (SSLLogger.isOn && SSLLogger.isOn("record")) { |
153 Debug.log("READ: " + |
148 SSLLogger.fine("READ: " + |
154 ProtocolVersion.valueOf(majorVersion, minorVersion) + |
149 ProtocolVersion.nameOf(majorVersion, minorVersion) + |
155 " " + Record.contentName(contentType) + ", length = " + |
150 " " + ContentType.nameOf(contentType) + ", length = " + |
156 contentLen); |
151 contentLen); |
157 } |
152 } |
158 |
153 |
159 int recLim = srcPos + DTLSRecord.headerSize + contentLen; |
154 int recLim = Math.addExact(srcPos, DTLSRecord.headerSize + contentLen); |
160 |
155 |
161 if (this.prevReadEpoch > recordEpoch) { |
156 if (this.readEpoch > recordEpoch) { |
162 // Reset the position of the packet buffer. |
157 // Reset the position of the packet buffer. |
163 packet.position(recLim); |
158 packet.position(recLim); |
164 if (debug != null && Debug.isOn("record")) { |
159 if (SSLLogger.isOn && SSLLogger.isOn("record")) { |
165 Debug.printHex("READ: discard this old record", recordEnS); |
160 SSLLogger.fine("READ: discard this old record", recordEnS); |
166 } |
161 } |
167 return null; |
162 return null; |
168 } |
163 } |
169 |
164 |
170 // Buffer next epoch message if necessary. |
165 // Buffer next epoch message if necessary. |
171 if (this.readEpoch < recordEpoch) { |
166 if (this.readEpoch < recordEpoch) { |
172 // Discard the record younger than the current epcoh if: |
167 // Discard the record younger than the current epcoh if: |
173 // 1. it is not a handshake message, or |
168 // 1. it is not a handshake message, or |
174 // 2. it is not of next epoch. |
169 // 3. it is not of next epoch. |
175 if (((contentType != Record.ct_handshake) && |
170 if ((contentType != ContentType.HANDSHAKE.id && |
176 (contentType != Record.ct_change_cipher_spec)) || |
171 contentType != ContentType.CHANGE_CIPHER_SPEC.id) || |
|
172 (reassembler == null && |
|
173 contentType != ContentType.HANDSHAKE.id) || |
177 (this.readEpoch < (recordEpoch - 1))) { |
174 (this.readEpoch < (recordEpoch - 1))) { |
178 |
175 |
179 packet.position(recLim); |
176 packet.position(recLim); |
180 |
177 |
181 if (debug != null && Debug.isOn("verbose")) { |
178 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
182 Debug.log("Premature record (epoch), discard it."); |
179 SSLLogger.fine("Premature record (epoch), discard it."); |
183 } |
180 } |
184 |
181 |
185 return null; |
182 return null; |
186 } |
183 } |
|
184 |
187 |
185 |
188 // Not ready to decrypt this record, may be an encrypted Finished |
186 // Not ready to decrypt this record, may be an encrypted Finished |
189 // message, need to buffer it. |
187 // message, need to buffer it. |
190 byte[] fragment = new byte[contentLen]; |
188 byte[] fragment = new byte[contentLen]; |
191 packet.get(fragment); // copy the fragment |
189 packet.get(fragment); // copy the fragment |
192 RecordFragment buffered = new RecordFragment(fragment, contentType, |
190 RecordFragment buffered = new RecordFragment(fragment, contentType, |
193 majorVersion, minorVersion, |
191 majorVersion, minorVersion, |
194 recordEnS, recordEpoch, recordSeq, true); |
192 recordEnS, recordEpoch, recordSeq, true); |
195 |
193 |
|
194 if (reassembler == null) { |
|
195 reassembler = new DTLSReassembler(recordEpoch); |
|
196 } |
196 reassembler.queueUpFragment(buffered); |
197 reassembler.queueUpFragment(buffered); |
197 |
198 |
198 // consume the full record in the packet buffer. |
199 // consume the full record in the packet buffer. |
199 packet.position(recLim); |
200 packet.position(recLim); |
200 |
201 |
201 return reassembler.acquirePlaintext(); |
202 Plaintext pt = reassembler.acquirePlaintext(); |
|
203 return pt == null ? null : new Plaintext[] { pt }; |
202 } |
204 } |
203 |
205 |
204 // |
206 // |
205 // Now, the message is of this epoch or the previous epoch. |
207 // Now, the message is of this epoch. |
206 // |
208 // |
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 |
209 // decrypt the fragment |
218 packet.limit(recLim); |
210 packet.limit(recLim); |
219 packet.position(srcPos + DTLSRecord.headerSize); |
211 packet.position(srcPos + DTLSRecord.headerSize); |
220 |
212 |
221 ByteBuffer plaintextFragment; |
213 ByteBuffer plaintextFragment; |
222 try { |
214 try { |
223 plaintextFragment = decrypt(decodeAuthenticator, |
215 Plaintext plaintext = |
224 decodeCipher, contentType, packet, recordEnS); |
216 readCipher.decrypt(contentType, packet, recordEnS); |
225 } catch (BadPaddingException bpe) { |
217 plaintextFragment = plaintext.fragment; |
226 if (debug != null && Debug.isOn("ssl")) { |
218 contentType = plaintext.contentType; |
227 Debug.log("Discard invalid record: " + bpe); |
219 } catch (GeneralSecurityException gse) { |
|
220 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { |
|
221 SSLLogger.fine("Discard invalid record: " + gse); |
228 } |
222 } |
229 |
223 |
230 // invalid, discard this record [section 4.1.2.7, RFC 6347] |
224 // invalid, discard this record [section 4.1.2.7, RFC 6347] |
231 return null; |
225 return null; |
232 } finally { |
226 } finally { |
233 // comsume a complete record |
227 // consume a complete record |
234 packet.limit(srcLim); |
228 packet.limit(srcLim); |
235 packet.position(recLim); |
229 packet.position(recLim); |
236 } |
230 } |
237 |
231 |
238 if (contentType != Record.ct_change_cipher_spec && |
232 if (contentType != ContentType.CHANGE_CIPHER_SPEC.id && |
239 contentType != Record.ct_handshake) { // app data or alert |
233 contentType != ContentType.HANDSHAKE.id) { // app data or alert |
240 // no retransmission |
234 // no retransmission |
241 // Cleanup the handshake reassembler if necessary. |
235 // Cleanup the handshake reassembler if necessary. |
242 if ((reassembler != null) && |
236 if ((reassembler != null) && |
243 (reassembler.handshakeEpoch < recordEpoch)) { |
237 (reassembler.handshakeEpoch < recordEpoch)) { |
244 if (debug != null && Debug.isOn("verbose")) { |
238 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
245 Debug.log("Cleanup the handshake reassembler"); |
239 SSLLogger.fine("Cleanup the handshake reassembler"); |
246 } |
240 } |
247 |
241 |
248 reassembler = null; |
242 reassembler = null; |
249 } |
243 } |
250 |
244 |
251 return new Plaintext(contentType, majorVersion, minorVersion, |
245 return new Plaintext[] { |
252 recordEpoch, Authenticator.toLong(recordEnS), |
246 new Plaintext(contentType, majorVersion, minorVersion, |
253 plaintextFragment); |
247 recordEpoch, Authenticator.toLong(recordEnS), |
254 } |
248 plaintextFragment)}; |
255 |
249 } |
256 if (contentType == Record.ct_change_cipher_spec) { |
250 |
|
251 if (contentType == ContentType.CHANGE_CIPHER_SPEC.id) { |
257 if (reassembler == null) { |
252 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); |
253 reassembler = new DTLSReassembler(recordEpoch); |
271 } |
254 } |
272 |
255 |
273 reassembler.queueUpChangeCipherSpec( |
256 reassembler.queueUpChangeCipherSpec( |
274 new RecordFragment(plaintextFragment, contentType, |
257 new RecordFragment(plaintextFragment, contentType, |
282 contentType, majorVersion, minorVersion, |
265 contentType, majorVersion, minorVersion, |
283 recordEnS, recordEpoch, recordSeq, plaintextFragment); |
266 recordEnS, recordEpoch, recordSeq, plaintextFragment); |
284 |
267 |
285 if (hsFrag == null) { |
268 if (hsFrag == null) { |
286 // invalid, discard this record |
269 // invalid, discard this record |
287 if (debug != null && Debug.isOn("verbose")) { |
270 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
288 Debug.log("Invalid handshake message, discard it."); |
271 SSLLogger.fine( |
|
272 "Invalid handshake message, discard it."); |
289 } |
273 } |
290 |
274 |
291 return null; |
275 return null; |
292 } |
276 } |
293 |
277 |
294 if (reassembler == null) { |
278 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); |
279 reassembler = new DTLSReassembler(recordEpoch); |
308 } |
280 } |
309 |
281 |
310 reassembler.queueUpHandshake(hsFrag); |
282 reassembler.queueUpHandshake(hsFrag); |
311 } |
283 } |
312 } |
284 } |
313 |
285 |
314 // Completed the read of the full record. Acquire the reassembled |
286 // Completed the read of the full record. Acquire the reassembled |
315 // messages. |
287 // messages. |
316 if (reassembler != null) { |
288 if (reassembler != null) { |
317 return reassembler.acquirePlaintext(); |
289 Plaintext pt = reassembler.acquirePlaintext(); |
318 } |
290 return pt == null ? null : new Plaintext[] { pt }; |
319 |
291 } |
320 if (debug != null && Debug.isOn("verbose")) { |
292 |
321 Debug.log("The reassembler is not initialized yet."); |
293 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
|
294 SSLLogger.fine("The reassembler is not initialized yet."); |
322 } |
295 } |
323 |
296 |
324 return null; |
297 return null; |
325 } |
298 } |
326 |
299 |
327 @Override |
300 @Override |
328 int bytesInCompletePacket(ByteBuffer packet) throws SSLException { |
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 { |
329 |
308 |
330 // DTLS length field is in bytes 11/12 |
309 // DTLS length field is in bytes 11/12 |
331 if (packet.remaining() < headerSize) { |
310 if (packet.remaining() < headerSize) { |
332 return -1; |
311 return -1; |
333 } |
312 } |
335 // Last sanity check that it's not a wild record |
314 // Last sanity check that it's not a wild record |
336 int pos = packet.position(); |
315 int pos = packet.position(); |
337 |
316 |
338 // Check the content type of the record. |
317 // Check the content type of the record. |
339 byte contentType = packet.get(pos); |
318 byte contentType = packet.get(pos); |
340 if (!Record.isValidContentType(contentType)) { |
319 if (ContentType.valueOf(contentType) == null) { |
341 throw new SSLException( |
320 throw new SSLException( |
342 "Unrecognized SSL message, plaintext connection?"); |
321 "Unrecognized SSL message, plaintext connection?"); |
343 } |
322 } |
344 |
323 |
345 // Check the protocol version of the record. |
324 // Check the protocol version of the record. |
346 ProtocolVersion recordVersion = |
325 byte majorVersion = packet.get(pos + 1); |
347 ProtocolVersion.valueOf(packet.get(pos + 1), packet.get(pos + 2)); |
326 byte minorVersion = packet.get(pos + 2); |
348 checkRecordVersion(recordVersion, false); |
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 } |
349 |
333 |
350 // Get the fragment length of the record. |
334 // Get the fragment length of the record. |
351 int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) + |
335 int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) + |
352 (packet.get(pos + 12) & 0xFF) + headerSize; |
336 (packet.get(pos + 12) & 0xFF) + headerSize; |
353 if (fragLen > Record.maxFragmentSize) { |
337 if (fragLen > Record.maxFragmentSize) { |
459 // the buffer if necessary. |
432 // the buffer if necessary. |
460 } |
433 } |
461 |
434 |
462 @Override |
435 @Override |
463 public int compareTo(RecordFragment o) { |
436 public int compareTo(RecordFragment o) { |
464 if (this.contentType == Record.ct_change_cipher_spec) { |
437 if (this.contentType == ContentType.CHANGE_CIPHER_SPEC.id) { |
465 if (o.contentType == Record.ct_change_cipher_spec) { |
438 if (o.contentType == ContentType.CHANGE_CIPHER_SPEC.id) { |
466 // Only one incoming ChangeCipherSpec message for an epoch. |
439 // Only one incoming ChangeCipherSpec message for an epoch. |
467 // |
440 // |
468 // Ignore duplicated ChangeCipherSpec messages. |
441 // Ignore duplicated ChangeCipherSpec messages. |
469 return Integer.compare(this.recordEpoch, o.recordEpoch); |
442 return Integer.compare(this.recordEpoch, o.recordEpoch); |
470 } else if ((this.recordEpoch == o.recordEpoch) && |
443 } else if ((this.recordEpoch == o.recordEpoch) && |
471 (o.contentType == Record.ct_handshake)) { |
444 (o.contentType == ContentType.HANDSHAKE.id)) { |
472 // ChangeCipherSpec is the latest message of an epoch. |
445 // ChangeCipherSpec is the latest message of an epoch. |
473 return 1; |
446 return 1; |
474 } |
447 } |
475 } else if (o.contentType == Record.ct_change_cipher_spec) { |
448 } else if (o.contentType == ContentType.CHANGE_CIPHER_SPEC.id) { |
476 if ((this.recordEpoch == o.recordEpoch) && |
449 if ((this.recordEpoch == o.recordEpoch) && |
477 (this.contentType == Record.ct_handshake)) { |
450 (this.contentType == ContentType.HANDSHAKE.id)) { |
478 // ChangeCipherSpec is the latest message of an epoch. |
451 // ChangeCipherSpec is the latest message of an epoch. |
479 return -1; |
452 return -1; |
480 } else { |
453 } else { |
481 // different epoch or this is not a handshake message |
454 // different epoch or this is not a handshake message |
482 return compareToSequence(o.recordEpoch, o.recordSeq); |
455 return compareToSequence(o.recordEpoch, o.recordSeq); |
1086 flightIsReady = false; |
1067 flightIsReady = false; |
1087 needToCheckFlight = false; |
1068 needToCheckFlight = false; |
1088 } |
1069 } |
1089 |
1070 |
1090 private Plaintext acquireCachedMessage() { |
1071 private Plaintext acquireCachedMessage() { |
1091 |
|
1092 RecordFragment rFrag = bufferedFragments.first(); |
1072 RecordFragment rFrag = bufferedFragments.first(); |
1093 if (readEpoch != rFrag.recordEpoch) { |
1073 if (readEpoch != rFrag.recordEpoch) { |
1094 if (readEpoch > rFrag.recordEpoch) { |
1074 if (readEpoch > rFrag.recordEpoch) { |
1095 // discard old records |
1075 // discard old records |
1096 if (debug != null && Debug.isOn("verbose")) { |
1076 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1097 Debug.log("Discard old buffered ciphertext fragments."); |
1077 SSLLogger.fine( |
|
1078 "Discard old buffered ciphertext fragments."); |
1098 } |
1079 } |
1099 bufferedFragments.remove(rFrag); // popup the fragment |
1080 bufferedFragments.remove(rFrag); // popup the fragment |
1100 } |
1081 } |
1101 |
1082 |
1102 // reset the flight |
1083 // reset the flight |
1103 if (flightIsReady) { |
1084 if (flightIsReady) { |
1104 flightIsReady = false; |
1085 flightIsReady = false; |
1105 } |
1086 } |
1106 |
1087 |
1107 if (debug != null && Debug.isOn("verbose")) { |
1088 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1108 Debug.log("Not yet ready to decrypt the cached fragments."); |
1089 SSLLogger.fine( |
|
1090 "Not yet ready to decrypt the cached fragments."); |
1109 } |
1091 } |
1110 return null; |
1092 return null; |
1111 } |
1093 } |
1112 |
1094 |
1113 bufferedFragments.remove(rFrag); // popup the fragment |
1095 bufferedFragments.remove(rFrag); // popup the fragment |
1114 |
1096 |
1115 ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment); |
1097 ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment); |
1116 ByteBuffer plaintextFragment = null; |
1098 ByteBuffer plaintextFragment = null; |
1117 try { |
1099 try { |
1118 plaintextFragment = decrypt(readAuthenticator, readCipher, |
1100 Plaintext plaintext = readCipher.decrypt( |
1119 rFrag.contentType, fragment, rFrag.recordEnS); |
1101 rFrag.contentType, fragment, rFrag.recordEnS); |
1120 } catch (BadPaddingException bpe) { |
1102 plaintextFragment = plaintext.fragment; |
1121 if (debug != null && Debug.isOn("verbose")) { |
1103 rFrag.contentType = plaintext.contentType; |
1122 Debug.log("Discard invalid record: " + bpe); |
1104 } catch (GeneralSecurityException gse) { |
|
1105 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
|
1106 SSLLogger.fine("Discard invalid record: ", gse); |
1123 } |
1107 } |
1124 |
1108 |
1125 // invalid, discard this record [section 4.1.2.7, RFC 6347] |
1109 // invalid, discard this record [section 4.1.2.7, RFC 6347] |
1126 return null; |
1110 return null; |
1127 } |
1111 } |
1128 |
1112 |
1129 // The ciphtext handshake message can only be Finished (the |
1113 // The ciphtext handshake message can only be Finished (the |
1130 // end of this flight), ClinetHello or HelloRequest (the |
1114 // end of this flight), ClinetHello or HelloRequest (the |
1131 // beginning of the next flight) message. Need not to check |
1115 // beginning of the next flight) message. Need not to check |
1132 // any ChangeCipherSpec message. |
1116 // any ChangeCipherSpec message. |
1133 if (rFrag.contentType == Record.ct_handshake) { |
1117 if (rFrag.contentType == ContentType.HANDSHAKE.id) { |
1134 while (plaintextFragment.remaining() > 0) { |
1118 while (plaintextFragment.remaining() > 0) { |
1135 HandshakeFragment hsFrag = parseHandshakeMessage( |
1119 HandshakeFragment hsFrag = parseHandshakeMessage( |
1136 rFrag.contentType, |
1120 rFrag.contentType, |
1137 rFrag.majorVersion, rFrag.minorVersion, |
1121 rFrag.majorVersion, rFrag.minorVersion, |
1138 rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq, |
1122 rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq, |
1139 plaintextFragment); |
1123 plaintextFragment); |
1140 |
1124 |
1141 if (hsFrag == null) { |
1125 if (hsFrag == null) { |
1142 // invalid, discard this record |
1126 // invalid, discard this record |
1143 if (debug != null && Debug.isOn("verbose")) { |
1127 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1144 Debug.printHex( |
1128 SSLLogger.fine( |
1145 "Invalid handshake fragment, discard it", |
1129 "Invalid handshake fragment, discard it", |
1146 plaintextFragment); |
1130 plaintextFragment); |
1147 } |
1131 } |
1148 return null; |
1132 return null; |
1149 } |
1133 } |
1170 } |
1154 } |
1171 |
1155 |
1172 private Plaintext acquireHandshakeMessage() { |
1156 private Plaintext acquireHandshakeMessage() { |
1173 |
1157 |
1174 RecordFragment rFrag = bufferedFragments.first(); |
1158 RecordFragment rFrag = bufferedFragments.first(); |
1175 if (rFrag.contentType == Record.ct_change_cipher_spec) { |
1159 if (rFrag.contentType == ContentType.CHANGE_CIPHER_SPEC.id) { |
1176 this.nextRecordEpoch = rFrag.recordEpoch + 1; |
1160 this.nextRecordEpoch = rFrag.recordEpoch + 1; |
1177 |
1161 |
1178 // For retransmissions, the next record sequence number is a |
1162 // For retransmissions, the next record sequence number is a |
1179 // positive value. Don't worry about it as the acquiring of |
1163 // positive value. Don't worry about it as the acquiring of |
1180 // the immediately followed Finished handshake message will |
1164 // the immediately followed Finished handshake message will |
1181 // reset the next record sequence number correctly. |
1165 // reset the next record sequence number correctly. |
1182 this.nextRecordSeq = 0; |
1166 this.nextRecordSeq = 0; |
1183 |
1167 |
1184 // Popup the fragment. |
1168 // Popup the fragment. |
1185 bufferedFragments.remove(rFrag); |
1169 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, |
1170 return new Plaintext(rFrag.contentType, |
1191 rFrag.majorVersion, rFrag.minorVersion, |
1171 rFrag.majorVersion, rFrag.minorVersion, |
1192 rFrag.recordEpoch, |
1172 rFrag.recordEpoch, |
1193 Authenticator.toLong(rFrag.recordEnS), |
1173 Authenticator.toLong(rFrag.recordEnS), |
1194 ByteBuffer.wrap(rFrag.fragment)); |
1174 ByteBuffer.wrap(rFrag.fragment)); |
1195 } else { // rFrag.contentType == Record.ct_handshake |
1175 } else { // rFrag.contentType == ContentType.HANDSHAKE.id |
1196 HandshakeFragment hsFrag = (HandshakeFragment)rFrag; |
1176 HandshakeFragment hsFrag = (HandshakeFragment)rFrag; |
1197 if ((hsFrag.messageLength == hsFrag.fragmentLength) && |
1177 if ((hsFrag.messageLength == hsFrag.fragmentLength) && |
1198 (hsFrag.fragmentOffset == 0)) { // no fragmentation |
1178 (hsFrag.fragmentOffset == 0)) { // no fragmentation |
1199 |
1179 |
1200 bufferedFragments.remove(rFrag); // popup the fragment |
1180 bufferedFragments.remove(rFrag); // popup the fragment |
1291 // the ChangeCipherSpec/Finished flight |
1273 // the ChangeCipherSpec/Finished flight |
1292 // |
1274 // |
1293 if (expectCCSFlight) { |
1275 if (expectCCSFlight) { |
1294 // Have the ChangeCipherSpec/Finished flight been received? |
1276 // Have the ChangeCipherSpec/Finished flight been received? |
1295 boolean isReady = hasFinishedMessage(bufferedFragments); |
1277 boolean isReady = hasFinishedMessage(bufferedFragments); |
1296 if (debug != null && Debug.isOn("verbose")) { |
1278 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1297 Debug.log( |
1279 SSLLogger.fine( |
1298 "Has the final flight been received? " + isReady); |
1280 "Has the final flight been received? " + isReady); |
1299 } |
1281 } |
1300 |
1282 |
1301 return isReady; |
1283 return isReady; |
1302 } |
1284 } |
1303 |
1285 |
1304 if (debug != null && Debug.isOn("verbose")) { |
1286 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1305 Debug.log("No flight is received yet."); |
1287 SSLLogger.fine("No flight is received yet."); |
1306 } |
1288 } |
1307 |
1289 |
1308 return false; |
1290 return false; |
1309 } |
1291 } |
1310 |
1292 |
1311 if ((flightType == HandshakeMessage.ht_client_hello) || |
1293 if ((flightType == SSLHandshake.CLIENT_HELLO.id) || |
1312 (flightType == HandshakeMessage.ht_hello_request) || |
1294 (flightType == SSLHandshake.HELLO_REQUEST.id) || |
1313 (flightType == HandshakeMessage.ht_hello_verify_request)) { |
1295 (flightType == SSLHandshake.HELLO_VERIFY_REQUEST.id)) { |
1314 |
1296 |
1315 // single handshake message flight |
1297 // single handshake message flight |
1316 boolean isReady = hasCompleted(flightType); |
1298 boolean isReady = hasCompleted(flightType); |
1317 if (debug != null && Debug.isOn("verbose")) { |
1299 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1318 Debug.log("Is the handshake message completed? " + isReady); |
1300 SSLLogger.fine( |
|
1301 "Is the handshake message completed? " + isReady); |
1319 } |
1302 } |
1320 |
1303 |
1321 return isReady; |
1304 return isReady; |
1322 } |
1305 } |
1323 |
1306 |
1324 // |
1307 // |
1325 // the ServerHello flight |
1308 // the ServerHello flight |
1326 // |
1309 // |
1327 if (flightType == HandshakeMessage.ht_server_hello) { |
1310 if (flightType == SSLHandshake.SERVER_HELLO.id) { |
1328 // Firstly, check the first flight handshake message. |
1311 // Firstly, check the first flight handshake message. |
1329 if (!hasCompleted(flightType)) { |
1312 if (!hasCompleted(flightType)) { |
1330 if (debug != null && Debug.isOn("verbose")) { |
1313 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1331 Debug.log( |
1314 SSLLogger.fine( |
1332 "The ServerHello message is not completed yet."); |
1315 "The ServerHello message is not completed yet."); |
1333 } |
1316 } |
1334 |
1317 |
1335 return false; |
1318 return false; |
1336 } |
1319 } |
1337 |
1320 |
1338 // |
1321 // |
1339 // an abbreviated handshake |
1322 // an abbreviated handshake |
1340 // |
1323 // |
1341 if (hasFinishedMessage(bufferedFragments)) { |
1324 if (hasFinishedMessage(bufferedFragments)) { |
1342 if (debug != null && Debug.isOn("verbose")) { |
1325 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1343 Debug.log("It's an abbreviated handshake."); |
1326 SSLLogger.fine("It's an abbreviated handshake."); |
1344 } |
1327 } |
1345 |
1328 |
1346 return true; |
1329 return true; |
1347 } |
1330 } |
1348 |
1331 |
1349 // |
1332 // |
1350 // a full handshake |
1333 // a full handshake |
1351 // |
1334 // |
1352 List<HoleDescriptor> holes = handshakeFlight.holesMap.get( |
1335 List<HoleDescriptor> holes = handshakeFlight.holesMap.get( |
1353 HandshakeMessage.ht_server_hello_done); |
1336 SSLHandshake.SERVER_HELLO_DONE.id); |
1354 if ((holes == null) || !holes.isEmpty()) { |
1337 if ((holes == null) || !holes.isEmpty()) { |
1355 // Not yet got the final message of the flight. |
1338 // Not yet got the final message of the flight. |
1356 if (debug != null && Debug.isOn("verbose")) { |
1339 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1357 Debug.log("Not yet got the ServerHelloDone message"); |
1340 SSLLogger.fine( |
|
1341 "Not yet got the ServerHelloDone message"); |
1358 } |
1342 } |
1359 |
1343 |
1360 return false; |
1344 return false; |
1361 } |
1345 } |
1362 |
1346 |
1363 // Have all handshake message been received? |
1347 // Have all handshake message been received? |
1364 boolean isReady = hasCompleted(bufferedFragments, |
1348 boolean isReady = hasCompleted(bufferedFragments, |
1365 handshakeFlight.minMessageSeq, |
1349 handshakeFlight.minMessageSeq, |
1366 handshakeFlight.maxMessageSeq); |
1350 handshakeFlight.maxMessageSeq); |
1367 if (debug != null && Debug.isOn("verbose")) { |
1351 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1368 Debug.log("Is the ServerHello flight (message " + |
1352 SSLLogger.fine( |
|
1353 "Is the ServerHello flight (message " + |
1369 handshakeFlight.minMessageSeq + "-" + |
1354 handshakeFlight.minMessageSeq + "-" + |
1370 handshakeFlight.maxMessageSeq + |
1355 handshakeFlight.maxMessageSeq + |
1371 ") completed? " + isReady); |
1356 ") completed? " + isReady); |
1372 } |
1357 } |
1373 |
1358 |
1379 // |
1364 // |
1380 // Note: need to consider more messages in this flight if |
1365 // Note: need to consider more messages in this flight if |
1381 // ht_supplemental_data and ht_certificate_url are |
1366 // ht_supplemental_data and ht_certificate_url are |
1382 // suppported in the future. |
1367 // suppported in the future. |
1383 // |
1368 // |
1384 if ((flightType == HandshakeMessage.ht_certificate) || |
1369 if ((flightType == SSLHandshake.CERTIFICATE.id) || |
1385 (flightType == HandshakeMessage.ht_client_key_exchange)) { |
1370 (flightType == SSLHandshake.CLIENT_KEY_EXCHANGE.id)) { |
1386 |
1371 |
1387 // Firstly, check the first flight handshake message. |
1372 // Firstly, check the first flight handshake message. |
1388 if (!hasCompleted(flightType)) { |
1373 if (!hasCompleted(flightType)) { |
1389 if (debug != null && Debug.isOn("verbose")) { |
1374 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1390 Debug.log( |
1375 SSLLogger.fine( |
1391 "The ClientKeyExchange or client Certificate " + |
1376 "The ClientKeyExchange or client Certificate " + |
1392 "message is not completed yet."); |
1377 "message is not completed yet."); |
1393 } |
1378 } |
1394 |
1379 |
1395 return false; |
1380 return false; |
1396 } |
1381 } |
1397 |
1382 |
1398 // Is client CertificateVerify a mandatory message? |
1383 // Is client CertificateVerify a mandatory message? |
1399 if (flightType == HandshakeMessage.ht_certificate) { |
1384 if (flightType == SSLHandshake.CERTIFICATE.id) { |
1400 if (needClientVerify(bufferedFragments) && |
1385 if (needClientVerify(bufferedFragments) && |
1401 !hasCompleted(ht_certificate_verify)) { |
1386 !hasCompleted(SSLHandshake.CERTIFICATE_VERIFY.id)) { |
1402 |
1387 |
1403 if (debug != null && Debug.isOn("verbose")) { |
1388 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1404 Debug.log( |
1389 SSLLogger.fine( |
1405 "Not yet have the CertificateVerify message"); |
1390 "Not yet have the CertificateVerify message"); |
1406 } |
1391 } |
1407 |
1392 |
1408 return false; |
1393 return false; |
1409 } |
1394 } |
1410 } |
1395 } |
1411 |
1396 |
1412 if (!hasFinishedMessage(bufferedFragments)) { |
1397 if (!hasFinishedMessage(bufferedFragments)) { |
1413 // not yet have the ChangeCipherSpec/Finished messages |
1398 // not yet have the ChangeCipherSpec/Finished messages |
1414 if (debug != null && Debug.isOn("verbose")) { |
1399 if (SSLLogger.isOn && SSLLogger.isOn("verbose")) { |
1415 Debug.log( |
1400 SSLLogger.fine( |
1416 "Not yet have the ChangeCipherSpec and " + |
1401 "Not yet have the ChangeCipherSpec and " + |
1417 "Finished messages"); |
1402 "Finished messages"); |
1418 } |
1403 } |
1419 |
1404 |
1420 return false; |
1405 return false; |