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