1 /* |
1 /* |
2 * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
45 |
40 |
46 int writeEpoch; |
41 int writeEpoch; |
47 |
42 |
48 int prevWriteEpoch; |
43 int prevWriteEpoch; |
49 Authenticator prevWriteAuthenticator; |
44 Authenticator prevWriteAuthenticator; |
50 CipherBox prevWriteCipher; |
45 SSLWriteCipher prevWriteCipher; |
51 |
46 |
52 private LinkedList<RecordMemo> alertMemos = new LinkedList<>(); |
47 private final LinkedList<RecordMemo> alertMemos = new LinkedList<>(); |
53 |
48 |
54 DTLSOutputRecord() { |
49 DTLSOutputRecord(HandshakeHash handshakeHash) { |
55 this.writeAuthenticator = new MAC(true); |
50 super(handshakeHash, SSLWriteCipher.nullDTlsWriteCipher()); |
56 |
51 |
57 this.writeEpoch = 0; |
52 this.writeEpoch = 0; |
58 this.prevWriteEpoch = 0; |
53 this.prevWriteEpoch = 0; |
59 this.prevWriteCipher = CipherBox.NULL; |
54 this.prevWriteCipher = SSLWriteCipher.nullDTlsWriteCipher(); |
60 this.prevWriteAuthenticator = new MAC(true); |
|
61 |
55 |
62 this.packetSize = DTLSRecord.maxRecordSize; |
56 this.packetSize = DTLSRecord.maxRecordSize; |
63 this.protocolVersion = ProtocolVersion.DEFAULT_DTLS; |
57 this.protocolVersion = ProtocolVersion.NONE; |
64 } |
58 } |
65 |
59 |
66 @Override |
60 @Override |
67 void changeWriteCiphers(Authenticator writeAuthenticator, |
61 void initHandshaker() { |
68 CipherBox writeCipher) throws IOException { |
62 // clean up |
69 |
63 fragmenter = null; |
70 encodeChangeCipherSpec(); |
64 } |
|
65 |
|
66 @Override |
|
67 void finishHandshake() { |
|
68 // Nothing to do here currently. |
|
69 } |
|
70 |
|
71 @Override |
|
72 void changeWriteCiphers(SSLWriteCipher writeCipher, |
|
73 boolean useChangeCipherSpec) throws IOException { |
|
74 if (useChangeCipherSpec) { |
|
75 encodeChangeCipherSpec(); |
|
76 } |
71 |
77 |
72 prevWriteCipher.dispose(); |
78 prevWriteCipher.dispose(); |
73 |
79 |
74 this.prevWriteAuthenticator = this.writeAuthenticator; |
|
75 this.prevWriteCipher = this.writeCipher; |
80 this.prevWriteCipher = this.writeCipher; |
76 this.prevWriteEpoch = this.writeEpoch; |
81 this.prevWriteEpoch = this.writeEpoch; |
77 |
82 |
78 this.writeAuthenticator = writeAuthenticator; |
|
79 this.writeCipher = writeCipher; |
83 this.writeCipher = writeCipher; |
80 this.writeEpoch++; |
84 this.writeEpoch++; |
81 |
85 |
82 this.isFirstAppOutputRecord = true; |
86 this.isFirstAppOutputRecord = true; |
83 |
87 |
84 // set the epoch number |
88 // set the epoch number |
85 this.writeAuthenticator.setEpochNumber(this.writeEpoch); |
89 this.writeCipher.authenticator.setEpochNumber(this.writeEpoch); |
86 } |
90 } |
87 |
91 |
88 @Override |
92 @Override |
89 void encodeAlert(byte level, byte description) throws IOException { |
93 void encodeAlert(byte level, byte description) throws IOException { |
90 RecordMemo memo = new RecordMemo(); |
94 RecordMemo memo = new RecordMemo(); |
91 |
95 |
92 memo.contentType = Record.ct_alert; |
96 memo.contentType = ContentType.ALERT.id; |
93 memo.majorVersion = protocolVersion.major; |
97 memo.majorVersion = protocolVersion.major; |
94 memo.minorVersion = protocolVersion.minor; |
98 memo.minorVersion = protocolVersion.minor; |
95 memo.encodeEpoch = writeEpoch; |
99 memo.encodeEpoch = writeEpoch; |
96 memo.encodeCipher = writeCipher; |
100 memo.encodeCipher = writeCipher; |
97 memo.encodeAuthenticator = writeAuthenticator; |
|
98 |
101 |
99 memo.fragment = new byte[2]; |
102 memo.fragment = new byte[2]; |
100 memo.fragment[0] = level; |
103 memo.fragment[0] = level; |
101 memo.fragment[1] = description; |
104 memo.fragment[1] = description; |
102 |
105 |
125 |
127 |
126 fragmenter.queueUpHandshake(source, offset, length); |
128 fragmenter.queueUpHandshake(source, offset, length); |
127 } |
129 } |
128 |
130 |
129 @Override |
131 @Override |
130 Ciphertext encode(ByteBuffer[] sources, int offset, int length, |
132 Ciphertext encode( |
|
133 ByteBuffer[] srcs, int srcsOffset, int srcsLength, |
|
134 ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws IOException { |
|
135 return encode(srcs, srcsOffset, srcsLength, dsts[0]); |
|
136 } |
|
137 |
|
138 private Ciphertext encode(ByteBuffer[] sources, int offset, int length, |
131 ByteBuffer destination) throws IOException { |
139 ByteBuffer destination) throws IOException { |
132 |
140 |
133 if (writeAuthenticator.seqNumOverflow()) { |
141 if (writeCipher.authenticator.seqNumOverflow()) { |
134 if (debug != null && Debug.isOn("ssl")) { |
142 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { |
135 System.out.println(Thread.currentThread().getName() + |
143 SSLLogger.fine( |
136 ", sequence number extremely close to overflow " + |
144 "sequence number extremely close to overflow " + |
137 "(2^64-1 packets). Closing connection."); |
145 "(2^64-1 packets). Closing connection."); |
138 } |
146 } |
139 |
147 |
140 throw new SSLHandshakeException("sequence number overflow"); |
148 throw new SSLHandshakeException("sequence number overflow"); |
141 } |
149 } |
142 |
150 |
|
151 // Don't process the incoming record until all of the buffered records |
|
152 // get handled. May need retransmission if no sources specified. |
|
153 if (!isEmpty() || sources == null || sources.length == 0) { |
|
154 Ciphertext ct = acquireCiphertext(destination); |
|
155 if (ct != null) { |
|
156 return ct; |
|
157 } |
|
158 } |
|
159 |
|
160 if (sources == null || sources.length == 0) { |
|
161 return null; |
|
162 } |
|
163 |
|
164 int srcsRemains = 0; |
|
165 for (int i = offset; i < offset + length; i++) { |
|
166 srcsRemains += sources[i].remaining(); |
|
167 } |
|
168 |
|
169 if (srcsRemains == 0) { |
|
170 return null; |
|
171 } |
|
172 |
143 // not apply to handshake message |
173 // not apply to handshake message |
144 int macLen = 0; |
|
145 if (writeAuthenticator instanceof MAC) { |
|
146 macLen = ((MAC)writeAuthenticator).MAClen(); |
|
147 } |
|
148 |
|
149 int fragLen; |
174 int fragLen; |
150 if (packetSize > 0) { |
175 if (packetSize > 0) { |
151 fragLen = Math.min(maxRecordSize, packetSize); |
176 fragLen = Math.min(maxRecordSize, packetSize); |
152 fragLen = writeCipher.calculateFragmentSize( |
177 fragLen = writeCipher.calculateFragmentSize( |
153 fragLen, macLen, headerSize); |
178 fragLen, headerSize); |
154 |
179 |
155 fragLen = Math.min(fragLen, Record.maxDataSize); |
180 fragLen = Math.min(fragLen, Record.maxDataSize); |
156 } else { |
181 } else { |
157 fragLen = Record.maxDataSize; |
182 fragLen = Record.maxDataSize; |
158 } |
183 } |
181 } |
206 } |
182 |
207 |
183 destination.limit(destination.position()); |
208 destination.limit(destination.position()); |
184 destination.position(dstContent); |
209 destination.position(dstContent); |
185 |
210 |
186 if ((debug != null) && Debug.isOn("record")) { |
211 if (SSLLogger.isOn && SSLLogger.isOn("record")) { |
187 System.out.println(Thread.currentThread().getName() + |
212 SSLLogger.fine( |
188 ", WRITE: " + protocolVersion + " " + |
213 "WRITE: " + protocolVersion + " " + |
189 Record.contentName(Record.ct_application_data) + |
214 ContentType.APPLICATION_DATA.name + |
190 ", length = " + destination.remaining()); |
215 ", length = " + destination.remaining()); |
191 } |
216 } |
192 |
217 |
193 // Encrypt the fragment and wrap up a record. |
218 // Encrypt the fragment and wrap up a record. |
194 long recordSN = encrypt(writeAuthenticator, writeCipher, |
219 long recordSN = encrypt(writeCipher, |
195 Record.ct_application_data, destination, |
220 ContentType.APPLICATION_DATA.id, destination, |
196 dstPos, dstLim, headerSize, |
221 dstPos, dstLim, headerSize, |
197 protocolVersion, true); |
222 protocolVersion); |
198 |
223 |
199 if ((debug != null) && Debug.isOn("packet")) { |
224 if (SSLLogger.isOn && SSLLogger.isOn("packet")) { |
200 ByteBuffer temporary = destination.duplicate(); |
225 ByteBuffer temporary = destination.duplicate(); |
201 temporary.limit(temporary.position()); |
226 temporary.limit(temporary.position()); |
202 temporary.position(dstPos); |
227 temporary.position(dstPos); |
203 Debug.printHex( |
228 SSLLogger.fine("Raw write", temporary); |
204 "[Raw write]: length = " + temporary.remaining(), |
|
205 temporary); |
|
206 } |
229 } |
207 |
230 |
208 // remain the limit unchanged |
231 // remain the limit unchanged |
209 destination.limit(dstLim); |
232 destination.limit(dstLim); |
210 |
233 |
211 return new Ciphertext(RecordType.RECORD_APPLICATION_DATA, recordSN); |
234 return new Ciphertext(ContentType.APPLICATION_DATA.id, |
212 } |
235 SSLHandshake.NOT_APPLICABLE.id, recordSN); |
213 |
236 } |
214 @Override |
237 |
215 Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException { |
238 private Ciphertext acquireCiphertext( |
|
239 ByteBuffer destination) throws IOException { |
216 if (alertMemos != null && !alertMemos.isEmpty()) { |
240 if (alertMemos != null && !alertMemos.isEmpty()) { |
217 RecordMemo memo = alertMemos.pop(); |
241 RecordMemo memo = alertMemos.pop(); |
218 |
|
219 int macLen = 0; |
|
220 if (memo.encodeAuthenticator instanceof MAC) { |
|
221 macLen = ((MAC)memo.encodeAuthenticator).MAClen(); |
|
222 } |
|
223 |
242 |
224 int dstPos = destination.position(); |
243 int dstPos = destination.position(); |
225 int dstLim = destination.limit(); |
244 int dstLim = destination.limit(); |
226 int dstContent = dstPos + headerSize + |
245 int dstContent = dstPos + headerSize + |
227 writeCipher.getExplicitNonceSize(); |
246 writeCipher.getExplicitNonceSize(); |
230 destination.put(memo.fragment); |
249 destination.put(memo.fragment); |
231 |
250 |
232 destination.limit(destination.position()); |
251 destination.limit(destination.position()); |
233 destination.position(dstContent); |
252 destination.position(dstContent); |
234 |
253 |
235 if ((debug != null) && Debug.isOn("record")) { |
254 if (SSLLogger.isOn && SSLLogger.isOn("record")) { |
236 System.out.println(Thread.currentThread().getName() + |
255 SSLLogger.fine( |
237 ", WRITE: " + protocolVersion + " " + |
256 "WRITE: " + protocolVersion + " " + |
238 Record.contentName(Record.ct_alert) + |
257 ContentType.ALERT.name + |
239 ", length = " + destination.remaining()); |
258 ", length = " + destination.remaining()); |
240 } |
259 } |
241 |
260 |
242 // Encrypt the fragment and wrap up a record. |
261 // Encrypt the fragment and wrap up a record. |
243 long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher, |
262 long recordSN = encrypt(memo.encodeCipher, |
244 Record.ct_alert, destination, dstPos, dstLim, headerSize, |
263 ContentType.ALERT.id, |
|
264 destination, dstPos, dstLim, headerSize, |
245 ProtocolVersion.valueOf(memo.majorVersion, |
265 ProtocolVersion.valueOf(memo.majorVersion, |
246 memo.minorVersion), true); |
266 memo.minorVersion)); |
247 |
267 |
248 if ((debug != null) && Debug.isOn("packet")) { |
268 if (SSLLogger.isOn && SSLLogger.isOn("packet")) { |
249 ByteBuffer temporary = destination.duplicate(); |
269 ByteBuffer temporary = destination.duplicate(); |
250 temporary.limit(temporary.position()); |
270 temporary.limit(temporary.position()); |
251 temporary.position(dstPos); |
271 temporary.position(dstPos); |
252 Debug.printHex( |
272 SSLLogger.fine("Raw write", temporary); |
253 "[Raw write]: length = " + temporary.remaining(), |
|
254 temporary); |
|
255 } |
273 } |
256 |
274 |
257 // remain the limit unchanged |
275 // remain the limit unchanged |
258 destination.limit(dstLim); |
276 destination.limit(dstLim); |
259 |
277 |
260 return new Ciphertext(RecordType.RECORD_ALERT, recordSN); |
278 return new Ciphertext(ContentType.ALERT.id, |
|
279 SSLHandshake.NOT_APPLICABLE.id, recordSN); |
261 } |
280 } |
262 |
281 |
263 if (fragmenter != null) { |
282 if (fragmenter != null) { |
264 return fragmenter.acquireCiphertext(destination); |
283 return fragmenter.acquireCiphertext(destination); |
265 } |
284 } |
334 flightIsReady = false; |
347 flightIsReady = false; |
335 } |
348 } |
336 |
349 |
337 RecordMemo memo = new RecordMemo(); |
350 RecordMemo memo = new RecordMemo(); |
338 |
351 |
339 memo.contentType = Record.ct_change_cipher_spec; |
352 memo.contentType = ContentType.CHANGE_CIPHER_SPEC.id; |
340 memo.majorVersion = protocolVersion.major; |
353 memo.majorVersion = protocolVersion.major; |
341 memo.minorVersion = protocolVersion.minor; |
354 memo.minorVersion = protocolVersion.minor; |
342 memo.encodeEpoch = writeEpoch; |
355 memo.encodeEpoch = writeEpoch; |
343 memo.encodeCipher = writeCipher; |
356 memo.encodeCipher = writeCipher; |
344 memo.encodeAuthenticator = writeAuthenticator; |
|
345 |
357 |
346 memo.fragment = new byte[1]; |
358 memo.fragment = new byte[1]; |
347 memo.fragment[0] = 1; |
359 memo.fragment[0] = 1; |
348 |
360 |
349 handshakeMemos.add(memo); |
361 handshakeMemos.add(memo); |
359 flightIsReady = false; |
371 flightIsReady = false; |
360 } |
372 } |
361 |
373 |
362 HandshakeMemo memo = new HandshakeMemo(); |
374 HandshakeMemo memo = new HandshakeMemo(); |
363 |
375 |
364 memo.contentType = Record.ct_handshake; |
376 memo.contentType = ContentType.HANDSHAKE.id; |
365 memo.majorVersion = protocolVersion.major; |
377 memo.majorVersion = protocolVersion.major; |
366 memo.minorVersion = protocolVersion.minor; |
378 memo.minorVersion = protocolVersion.minor; |
367 memo.encodeEpoch = writeEpoch; |
379 memo.encodeEpoch = writeEpoch; |
368 memo.encodeCipher = writeCipher; |
380 memo.encodeCipher = writeCipher; |
369 memo.encodeAuthenticator = writeAuthenticator; |
|
370 |
381 |
371 memo.handshakeType = buf[offset]; |
382 memo.handshakeType = buf[offset]; |
372 memo.messageSequence = messageSequence++; |
383 memo.messageSequence = messageSequence++; |
373 memo.acquireOffset = 0; |
384 memo.acquireOffset = 0; |
374 memo.fragment = new byte[length - 4]; // 4: header size |
385 memo.fragment = new byte[length - 4]; // 4: header size |
377 System.arraycopy(buf, offset + 4, memo.fragment, 0, length - 4); |
388 System.arraycopy(buf, offset + 4, memo.fragment, 0, length - 4); |
378 |
389 |
379 handshakeHashing(memo, memo.fragment); |
390 handshakeHashing(memo, memo.fragment); |
380 handshakeMemos.add(memo); |
391 handshakeMemos.add(memo); |
381 |
392 |
382 if ((memo.handshakeType == HandshakeMessage.ht_client_hello) || |
393 if ((memo.handshakeType == SSLHandshake.CLIENT_HELLO.id) || |
383 (memo.handshakeType == HandshakeMessage.ht_hello_request) || |
394 (memo.handshakeType == SSLHandshake.HELLO_REQUEST.id) || |
384 (memo.handshakeType == |
395 (memo.handshakeType == |
385 HandshakeMessage.ht_hello_verify_request) || |
396 SSLHandshake.HELLO_VERIFY_REQUEST.id) || |
386 (memo.handshakeType == HandshakeMessage.ht_server_hello_done) || |
397 (memo.handshakeType == SSLHandshake.SERVER_HELLO_DONE.id) || |
387 (memo.handshakeType == HandshakeMessage.ht_finished)) { |
398 (memo.handshakeType == SSLHandshake.FINISHED.id)) { |
388 |
399 |
389 flightIsReady = true; |
400 flightIsReady = true; |
390 } |
401 } |
391 } |
402 } |
392 |
403 |
399 } |
410 } |
400 } |
411 } |
401 |
412 |
402 RecordMemo memo = handshakeMemos.get(acquireIndex); |
413 RecordMemo memo = handshakeMemos.get(acquireIndex); |
403 HandshakeMemo hsMemo = null; |
414 HandshakeMemo hsMemo = null; |
404 if (memo.contentType == Record.ct_handshake) { |
415 if (memo.contentType == ContentType.HANDSHAKE.id) { |
405 hsMemo = (HandshakeMemo)memo; |
416 hsMemo = (HandshakeMemo)memo; |
406 } |
|
407 |
|
408 int macLen = 0; |
|
409 if (memo.encodeAuthenticator instanceof MAC) { |
|
410 macLen = ((MAC)memo.encodeAuthenticator).MAClen(); |
|
411 } |
417 } |
412 |
418 |
413 // ChangeCipherSpec message is pretty small. Don't worry about |
419 // ChangeCipherSpec message is pretty small. Don't worry about |
414 // the fragmentation of ChangeCipherSpec record. |
420 // the fragmentation of ChangeCipherSpec record. |
415 int fragLen; |
421 int fragLen; |
416 if (packetSize > 0) { |
422 if (packetSize > 0) { |
417 fragLen = Math.min(maxRecordSize, packetSize); |
423 fragLen = Math.min(maxRecordSize, packetSize); |
418 fragLen = memo.encodeCipher.calculateFragmentSize( |
424 fragLen = memo.encodeCipher.calculateFragmentSize( |
419 fragLen, macLen, 25); // 25: header size |
425 fragLen, 25); // 25: header size |
420 // 13: DTLS record |
426 // 13: DTLS record |
421 // 12: DTLS handshake message |
427 // 12: DTLS handshake message |
422 fragLen = Math.min(fragLen, Record.maxDataSize); |
428 fragLen = Math.min(fragLen, Record.maxDataSize); |
423 } else { |
429 } else { |
424 fragLen = Record.maxDataSize; |
430 fragLen = Record.maxDataSize; |
457 } |
463 } |
458 |
464 |
459 dstBuf.limit(dstBuf.position()); |
465 dstBuf.limit(dstBuf.position()); |
460 dstBuf.position(dstContent); |
466 dstBuf.position(dstContent); |
461 |
467 |
462 if ((debug != null) && Debug.isOn("record")) { |
468 if (SSLLogger.isOn && SSLLogger.isOn("record")) { |
463 System.out.println(Thread.currentThread().getName() + |
469 SSLLogger.fine( |
464 ", WRITE: " + protocolVersion + " " + |
470 "WRITE: " + protocolVersion + " " + |
465 Record.contentName(memo.contentType) + |
471 ContentType.nameOf(memo.contentType) + |
466 ", length = " + dstBuf.remaining()); |
472 ", length = " + dstBuf.remaining()); |
467 } |
473 } |
468 |
474 |
469 // Encrypt the fragment and wrap up a record. |
475 // Encrypt the fragment and wrap up a record. |
470 long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher, |
476 long recordSN = encrypt(memo.encodeCipher, |
471 memo.contentType, dstBuf, |
477 memo.contentType, dstBuf, |
472 dstPos, dstLim, headerSize, |
478 dstPos, dstLim, headerSize, |
473 ProtocolVersion.valueOf(memo.majorVersion, |
479 ProtocolVersion.valueOf(memo.majorVersion, |
474 memo.minorVersion), true); |
480 memo.minorVersion)); |
475 |
481 |
476 if ((debug != null) && Debug.isOn("packet")) { |
482 if (SSLLogger.isOn && SSLLogger.isOn("packet")) { |
477 ByteBuffer temporary = dstBuf.duplicate(); |
483 ByteBuffer temporary = dstBuf.duplicate(); |
478 temporary.limit(temporary.position()); |
484 temporary.limit(temporary.position()); |
479 temporary.position(dstPos); |
485 temporary.position(dstPos); |
480 Debug.printHex( |
486 SSLLogger.fine( |
481 "[Raw write]: length = " + temporary.remaining(), |
487 "Raw write (" + temporary.remaining() + ")", temporary); |
482 temporary); |
|
483 } |
488 } |
484 |
489 |
485 // remain the limit unchanged |
490 // remain the limit unchanged |
486 dstBuf.limit(dstLim); |
491 dstBuf.limit(dstLim); |
487 |
492 |
490 hsMemo.acquireOffset += fragLen; |
495 hsMemo.acquireOffset += fragLen; |
491 if (hsMemo.acquireOffset == hsMemo.fragment.length) { |
496 if (hsMemo.acquireOffset == hsMemo.fragment.length) { |
492 acquireIndex++; |
497 acquireIndex++; |
493 } |
498 } |
494 |
499 |
495 return new Ciphertext(RecordType.valueOf( |
500 return new Ciphertext(hsMemo.contentType, |
496 hsMemo.contentType, hsMemo.handshakeType), recordSN); |
501 hsMemo.handshakeType, recordSN); |
497 } else { |
502 } else { |
498 acquireIndex++; |
503 acquireIndex++; |
499 return new Ciphertext( |
504 return new Ciphertext(ContentType.CHANGE_CIPHER_SPEC.id, |
500 RecordType.RECORD_CHANGE_CIPHER_SPEC, recordSN); |
505 SSLHandshake.NOT_APPLICABLE.id, recordSN); |
501 } |
506 } |
502 } |
507 } |
503 |
508 |
504 private void handshakeHashing(HandshakeMemo hsFrag, byte[] hsBody) { |
509 private void handshakeHashing(HandshakeMemo hsFrag, byte[] hsBody) { |
505 |
510 |
506 byte hsType = hsFrag.handshakeType; |
511 byte hsType = hsFrag.handshakeType; |
507 if ((hsType == HandshakeMessage.ht_hello_request) || |
512 if (!handshakeHash.isHashable(hsType)) { |
508 (hsType == HandshakeMessage.ht_hello_verify_request)) { |
|
509 |
|
510 // omitted from handshake hash computation |
513 // omitted from handshake hash computation |
511 return; |
514 return; |
512 } |
|
513 |
|
514 if ((hsFrag.messageSequence == 0) && |
|
515 (hsType == HandshakeMessage.ht_client_hello)) { |
|
516 |
|
517 // omit initial ClientHello message |
|
518 // |
|
519 // 2: ClientHello.client_version |
|
520 // 32: ClientHello.random |
|
521 int sidLen = hsBody[34]; |
|
522 |
|
523 if (sidLen == 0) { // empty session_id, initial handshake |
|
524 return; |
|
525 } |
|
526 } |
515 } |
527 |
516 |
528 // calculate the DTLS header |
517 // calculate the DTLS header |
529 byte[] temporary = new byte[12]; // 12: handshake header size |
518 byte[] temporary = new byte[12]; // 12: handshake header size |
530 |
519 |
548 // Handshake.fragment_length |
537 // Handshake.fragment_length |
549 temporary[9] = temporary[1]; |
538 temporary[9] = temporary[1]; |
550 temporary[10] = temporary[2]; |
539 temporary[10] = temporary[2]; |
551 temporary[11] = temporary[3]; |
540 temporary[11] = temporary[3]; |
552 |
541 |
553 if ((hsType != HandshakeMessage.ht_finished) && |
542 handshakeHash.deliver(temporary, 0, 12); |
554 (hsType != HandshakeMessage.ht_certificate_verify)) { |
543 handshakeHash.deliver(hsBody, 0, hsBody.length); |
555 |
|
556 handshakeHash.update(temporary, 0, 12); |
|
557 handshakeHash.update(hsBody, 0, hsBody.length); |
|
558 } else { |
|
559 // Reserve until this handshake message has been processed. |
|
560 handshakeHash.reserve(temporary, 0, 12); |
|
561 handshakeHash.reserve(hsBody, 0, hsBody.length); |
|
562 } |
|
563 |
|
564 } |
544 } |
565 |
545 |
566 boolean isEmpty() { |
546 boolean isEmpty() { |
567 if (!flightIsReady || handshakeMemos.isEmpty() || |
547 if (!flightIsReady || handshakeMemos.isEmpty() || |
568 acquireIndex >= handshakeMemos.size()) { |
548 acquireIndex >= handshakeMemos.size()) { |