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