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